[magics] 01/10: New upstream 2.26.2
Alastair McKinstry
mckinstry at moszumanska.debian.org
Sun Jan 10 15:59:09 UTC 2016
This is an automated email from the git hooks/post-receive script.
mckinstry pushed a commit to branch debian/master
in repository magics.
commit d848ba5f664eba4e65a10597041d7d36553167f9
Author: Alastair McKinstry <mckinstry at debian.org>
Date: Mon Jan 4 03:55:33 2016 +0000
New upstream 2.26.2
---
CMakeLists.txt | 414 +--
INSTALL | 229 +-
NOTICE | 63 +
VERSION.cmake | 7 +-
apps/MagMLInterpretor/CMakeLists.txt | 4 +-
apps/metgram/CMakeLists.txt | 13 +-
apps/metgram/metgram.py | 130 +
bin/CMakeLists.txt | 3 +
bin/ecbuild | 422 +++
cmake/CheckFortranSourceCompiles.cmake | 2 +-
cmake/FindAEC.cmake | 2 -
cmake/FindArmadillo.cmake | 33 +-
cmake/FindEMOS.cmake | 2 -
cmake/FindEcLib.cmake | 49 -
cmake/FindEcregrid.cmake | 48 -
cmake/FindLibIFort.cmake | 47 +
cmake/FindMKL.cmake | 77 +
cmake/FindNetCDF.cmake | 145 +-
cmake/FindNetCDF3.cmake | 65 +-
cmake/FindOpenCL.cmake | 67 +
cmake/FindOpenJPEG.cmake | 3 +-
cmake/FindPango.cmake | 2 -
cmake/FindPangoCairo.cmake | 13 +-
cmake/FindProj4.cmake | 10 +-
cmake/FindSZip.cmake | 2 -
cmake/FindScin.cmake | 48 -
cmake/FindTrilinos.cmake | 3 -
cmake/FindViennaCL.cmake | 38 +
cmake/Findgrib_api.cmake | 2 -
cmake/Findodb_api.cmake | 2 -
cmake/Findspot.cmake | 2 -
cmake/VERSION.cmake | 4 +-
cmake/contrib/FindEigen3.cmake | 10 +-
cmake/contrib/FindFFTW.cmake | 52 +-
cmake/contrib/FindNetCDF4.cmake | 30 +-
cmake/ecbuild_add_c_flags.cmake | 79 +
cmake/ecbuild_add_cxx11_flags.cmake | 20 +-
cmake/ecbuild_add_cxx_flags.cmake | 79 +
cmake/ecbuild_add_executable.cmake | 433 ++-
cmake/ecbuild_add_extra_search_paths.cmake | 23 +-
cmake/ecbuild_add_fortran_flags.cmake | 85 +
cmake/ecbuild_add_library.cmake | 737 ++--
cmake/ecbuild_add_option.cmake | 193 +-
cmake/ecbuild_add_persistent.cmake | 92 +-
cmake/ecbuild_add_resources.cmake | 95 +-
cmake/ecbuild_add_test.cmake | 610 ++--
cmake/ecbuild_append_to_rpath.cmake | 35 +-
cmake/ecbuild_bundle.cmake | 338 +-
cmake/ecbuild_cache.cmake | 34 +-
...e.cmake => ecbuild_check_c_source_return.cmake} | 93 +-
cmake/ecbuild_check_compiler.cmake | 44 +-
cmake/ecbuild_check_cxx11.cmake | 76 +-
...cmake => ecbuild_check_cxx_source_return.cmake} | 87 +-
...e => ecbuild_check_fortran_source_return.cmake} | 86 +-
cmake/ecbuild_check_functions.cmake | 65 +-
cmake/ecbuild_check_os.cmake | 80 +-
cmake/ecbuild_config.h.in | 25 +
cmake/ecbuild_debug_var.cmake | 12 +
cmake/ecbuild_declare_project.cmake | 242 +-
cmake/ecbuild_define_build_types.cmake | 43 +-
cmake/ecbuild_define_options.cmake | 10 +-
cmake/ecbuild_define_uninstall.cmake | 7 +
cmake/ecbuild_dont_pack.cmake | 82 +
cmake/ecbuild_download_resource.cmake | 47 +
cmake/ecbuild_echo_targets.cmake | 67 +-
cmake/ecbuild_enable_fortran.cmake | 80 +-
cmake/ecbuild_features.cmake | 121 +
cmake/ecbuild_find_fortranlibs.cmake | 210 +-
cmake/ecbuild_find_lexyacc.cmake | 96 +-
cmake/ecbuild_find_mpi.cmake | 126 +-
cmake/ecbuild_find_omp.cmake | 72 +-
cmake/ecbuild_find_package.cmake | 399 ++-
cmake/ecbuild_find_perl.cmake | 76 +-
cmake/ecbuild_find_python.cmake | 74 +-
cmake/ecbuild_generate_config_headers.cmake | 62 +-
cmake/ecbuild_generate_rpc.cmake | 31 +-
cmake/ecbuild_generate_yy.cmake | 226 +-
cmake/ecbuild_get_cxx11_flags.cmake | 71 +
cmake/ecbuild_get_date.cmake | 28 +-
cmake/ecbuild_get_test_data.cmake | 248 +-
cmake/ecbuild_git.cmake | 307 ++
...package.cmake => ecbuild_install_project.cmake} | 175 +-
cmake/ecbuild_list_extra_search_paths.cmake | 53 +-
cmake/ecbuild_list_macros.cmake | 33 +
cmake/ecbuild_log.cmake | 129 +
cmake/ecbuild_pkgconfig.cmake | 176 +-
cmake/ecbuild_policies.cmake | 63 +
cmake/ecbuild_print_summary.cmake | 177 +-
cmake/ecbuild_project_files.cmake | 60 +-
cmake/ecbuild_requires_macro_version.cmake | 12 +
cmake/ecbuild_separate_sources.cmake | 32 +-
cmake/ecbuild_setup_test_framework.cmake | 47 +-
cmake/ecbuild_system.cmake | 381 +--
cmake/ecbuild_uninstall.cmake.in | 21 +
cmake/ecbuild_use_package.cmake | 352 +-
cmake/ecbuild_warn_unused_files.cmake | 29 +-
cmake/pkg-config.pc.in | 8 +-
cmake/project-config.cmake.in | 18 +-
cmake/pymain.c | 5 +
magics-config.in | 323 --
magics-import.cmake.in | 5 +
project_summary.cmake | 6 +-
python/Magics/CMakeLists.txt | 18 +-
python/Magics/Magics_interface.cc | 3 +
python/Magics/macro.py | 2 +
share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake | 81 +
share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake | 73 +
share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake | 76 +
share/magics/Fonts.dat | 8 +-
share/magics/obs.xml | 2 +-
share/magics/symbols.svg | 1543 +++++----
share/magics/title_template.xml | 4 +
src/CMakeLists.txt | 88 +-
src/basic/BasicGraphicsObject.cc | 1 -
src/basic/BasicGraphicsObject.h | 21 +-
src/basic/BasicSceneObject.cc | 2 +-
src/basic/BasicSceneObject.h | 40 +-
src/basic/CMakeLists.txt | 2 +-
src/basic/FortranMagics.cc | 205 +-
src/basic/FortranMagics.h | 2 +-
src/basic/Layer.cc | 22 +-
src/basic/Layer.h | 2 +-
src/basic/LegendVisitor.cc | 7 +-
src/basic/LegendVisitor.h | 10 +-
src/basic/MagnifierVisitor.cc | 2 +-
src/basic/MultiVisdef.cc | 2 +-
src/basic/RootSceneNode.cc | 4 +-
src/basic/SceneNode.cc | 5 +-
src/basic/SceneVisitor.cc | 16 +-
src/basic/SceneVisitor.h | 47 +-
src/basic/TagHandler.cc | 3 +-
src/basic/TextVisitor.cc | 11 +-
src/basic/ViewNode.cc | 53 +-
src/basic/ViewNode.h | 15 +-
src/basic/Visdef.h | 2 +-
src/basic/VisualAction.cc | 2 +-
src/basic/VisualAction.h | 2 +-
src/basic/XmlMagics.cc | 177 +-
src/basic/XmlMagics.h | 2 +-
src/common/AnimationRules.cc | 2 +-
src/common/AutoLocker.cc | 24 +-
src/common/BaseParameter.h | 18 +-
src/common/BasePointsHandler.h | 9 +-
src/common/CMakeLists.txt | 4 +-
src/common/Coordinate.h | 12 +-
src/common/Data.h | 7 +-
src/common/Factory.cc | 2 +-
src/common/GeoRectangularProjection.cc | 6 +-
src/common/{Matrix.cc => GribInterpretor.h} | 9 +-
src/common/Layout.cc | 45 +-
src/common/Layout.h | 8 +-
src/common/MagException.h | 30 +-
src/common/MagExceptions.h | 16 +-
src/common/MagTranslator.h | 37 +-
src/common/MagicsCalls.cc | 32 +-
src/common/MagicsSingleton.h | 6 +-
src/common/Matrix.cc | 8 +-
src/common/Matrix.h | 2 +-
src/common/MatrixHandler.h | 7 +-
src/common/Node.cc | 2 +-
src/common/OutputFactory.cc | 15 +-
src/common/OutputFactory.h | 15 +-
src/common/OutputHandler.cc | 11 +-
src/common/ParameterManager.h | 33 +-
src/common/PolarStereographicProjection.cc | 10 +-
src/common/PolarStereographicProjection.h | 1 +
src/common/Proj4Projection.cc | 11 +-
src/common/Proj4Projection.h | 1 +
src/common/TableDefinition.h | 14 +-
src/common/TaylorProjection.cc | 2 +-
src/common/ThreadControler.cc | 2 +-
src/common/Transformation.h | 17 +-
src/common/UserPoint.h | 26 +-
src/common/magics_api.h | 2 +-
src/decoders/BinningObject.cc | 2 +-
src/decoders/BoxPlotDecoder.h | 2 +-
src/decoders/CMakeLists.txt | 10 +-
src/decoders/ClassicMtgDecoder.cc | 2 +-
src/decoders/ClassicMtgDecoder.h | 2 +-
src/decoders/EpsXmlInput.h | 2 +-
src/decoders/EpsgramDecoder.cc | 2 +-
src/decoders/EpsgramDecoder.h | 2 +-
src/decoders/GeoPointsDecoder.cc | 33 +-
src/decoders/GribAddressMode.h | 30 +-
src/decoders/GribDecoder.cc | 3562 ++++++++++----------
src/decoders/GribDecoder.h | 133 +-
src/decoders/GribInterpretor.h | 31 +
src/decoders/GribRegularInterpretor.cc | 3230 ++++++++++--------
src/decoders/GribRegularInterpretor.h | 6 +
src/decoders/GribSatelliteInterpretor.cc | 12 +-
src/decoders/ImportAction.h | 2 +-
src/decoders/InputData.cc | 21 +-
src/decoders/InputMatrix.cc | 12 +-
src/decoders/InputMatrix.h | 3 +-
src/decoders/InputMatrixInterpretor.cc | 23 +-
src/decoders/LandgramDecoder.cc | 2 +-
src/decoders/MatrixTestDecoder.cc | 2 +-
src/decoders/MatrixTestDecoder.h | 27 +-
src/decoders/Netcdf.cc | 4 +-
src/decoders/NetcdfDecoder.h | 3 +-
src/decoders/NetcdfGeoMatrixInterpretor.cc | 8 +-
src/decoders/NetcdfGeoMatrixInterpretor.h | 2 +-
src/decoders/NetcdfGeopointsInterpretor.cc | 2 +-
src/decoders/NetcdfGeopointsInterpretor.h | 80 +-
src/decoders/NetcdfInterpretor.cc | 18 +-
src/decoders/NetcdfInterpretor.h | 2 +-
src/decoders/NetcdfMatrixInterpretor.cc | 35 +-
src/decoders/NetcdfMatrixInterpretor.h | 1 +
src/decoders/NetcdfOrcaInterpretor.cc | 36 +-
src/decoders/NetcdfOrcaInterpretor.h | 3 +-
src/decoders/NetcdfVectorInterpretor.cc | 62 +-
src/decoders/NetcdfVectorInterpretor.h | 4 +-
src/decoders/ObsDecoder.cc | 2 +-
src/decoders/ShapeDecoder.h | 23 +-
src/decoders/TitleTemplate.h | 2 +-
src/drivers/BaseDriver.cc | 233 +-
src/drivers/BaseDriverSymbols.h | 89 +-
src/drivers/BaseDriverWind.h | 32 +-
src/drivers/BinaryDriver.cc | 2 +-
src/drivers/CMakeLists.txt | 108 +-
src/drivers/CairoDriver.cc | 222 +-
src/drivers/CairoDriver.h | 7 +-
src/drivers/GeoJsonDriver.cc | 654 ++++
src/drivers/GeoJsonDriver.h | 142 +
src/drivers/KMLDriver.cc | 8 +-
src/drivers/MgQ/MgQLayoutItem.cc | 15 +-
src/drivers/MgQ/MgQLayoutItem.h | 5 +-
src/drivers/MgQ/MgQPolylineSetItem.cc | 2 +-
src/drivers/MgQ/MgQScene.cc | 33 +-
src/drivers/MgQ/MgQSceneItem.cc | 2 +-
src/drivers/PostScriptDriver.cc | 8 +-
src/drivers/QtDriver.cc | 134 +-
src/drivers/SVGDriver.cc | 49 +-
src/drivers/libimagequant/COPYRIGHT | 36 +
src/drivers/libimagequant/MANUAL.md | 478 +++
src/drivers/libimagequant/Makefile | 65 +
src/drivers/libimagequant/blur.c | 112 +
src/drivers/libimagequant/blur.h | 4 +
src/drivers/libimagequant/configure | 205 ++
src/drivers/libimagequant/libimagequant.c | 1648 +++++++++
src/drivers/libimagequant/libimagequant.h | 109 +
src/drivers/libimagequant/mediancut.c | 507 +++
src/drivers/libimagequant/mediancut.h | 2 +
src/drivers/libimagequant/mempool.c | 63 +
src/drivers/libimagequant/mempool.h | 13 +
src/drivers/libimagequant/nearest.c | 241 ++
src/drivers/libimagequant/nearest.h | 8 +
src/drivers/libimagequant/pam.c | 278 ++
src/drivers/libimagequant/pam.h | 290 ++
src/drivers/libimagequant/pngquant.c | 295 ++
src/drivers/libimagequant/pngquant.h | 71 +
src/drivers/libimagequant/rwpng.c | 615 ++++
src/drivers/libimagequant/rwpng.h | 124 +
src/drivers/libimagequant/viter.c | 89 +
src/drivers/libimagequant/viter.h | 19 +
src/drivers/minizip/zip.c | 4 +-
src/eckit_readers/CMakeLists.txt | 2 +-
src/eckit_readers/TableReader.cc | 2 +-
src/libMagWrapper/MagPlus.cc | 427 ++-
src/libMagWrapper/MagPlus.h | 6 +-
src/libMagWrapper/MagRequest.h | 4 +-
src/magics.h | 7 +-
src/magics.pc.in | 13 -
src/magics_config.h.in | 20 +-
src/oda/OdaDecoder.cc | 14 +-
src/params/BaseDriver.xml | 20 +-
src/params/CMakeLists.txt | 12 +-
src/params/CairoDriver.xml | 8 +-
src/params/FortranViewNode.xml | 4 +
src/params/GeoJSon.xml | 15 +
src/params/GeoJsonDriver.xml | 28 +
src/params/GeoPointsDecoder.xml | 3 +
src/params/GribDecoder.xml | 8 +-
src/params/GribLoop.xml | 19 +-
src/params/InputMatrix.xml | 4 +
src/params/LabelPlotting.xml | 19 +-
src/params/LegendVisitor.xml | 6 +-
src/params/MarkerShadingTechnique.xml | 13 +-
src/params/NetcdfInterpretor.xml | 8 +-
src/params/ObsPlotting.xml | 6 +-
src/params/OutputHandler.xml | 8 +-
src/params/SVGDriver.xml | 4 +-
src/params/Streamlines.xml | 38 +-
src/params/SymbolAdvancedTableMode.xml | 5 +-
src/params/SymbolIndividualMode.xml | 4 +-
src/params/SymbolPlotting.xml | 23 +-
src/params/WrepJSon.xml | 5 +-
src/visualisers/AxisMethod.h | 2 +-
src/visualisers/CMakeLists.txt | 2 +-
src/visualisers/CalcStreamlines.cc | 12 +-
src/visualisers/CalcStreamlines.h | 2 +
src/visualisers/Coastlines.cc | 2 +-
src/visualisers/Contour.cc | 3 +
src/visualisers/ContourLibrary.cc | 30 +-
src/visualisers/ContourLibrary.h | 18 +-
src/visualisers/CountSelectionType.cc | 13 +-
src/visualisers/EpsGraph.cc | 64 +-
src/visualisers/Filter.h | 20 +-
src/visualisers/HeightTechnique.cc | 2 +-
src/visualisers/Histogram.h | 2 +-
src/visualisers/IsoHelper.cc | 2 +-
src/visualisers/IsoHighlight.h | 2 +-
src/visualisers/IsoPlot.cc | 104 +-
src/visualisers/IsoPlot.h | 4 +-
src/visualisers/LabelPlotting.h | 5 +-
src/visualisers/LevelSelection.cc | 11 +-
src/visualisers/MarkerShadingTechnique.cc | 22 +-
src/visualisers/ObsItem.h | 22 +-
src/visualisers/ObsItemFamily.cc | 365 +-
src/visualisers/ObsItemFamily.h | 34 +-
src/visualisers/ObsPlotting.cc | 3 +
src/visualisers/ObsTable.cc | 3 +-
src/visualisers/SegmentJoiner.cc | 4 +-
src/visualisers/SegmentJoiner.h | 3 +-
src/visualisers/ShadingTechnique.h | 2 +-
src/visualisers/Streamlines.cc | 93 +-
src/visualisers/SymbolAdvancedTableMode.cc | 44 +-
src/visualisers/SymbolMode.cc | 5 +-
src/visualisers/SymbolPlotting.cc | 6 +-
src/visualisers/SymbolPlotting.h | 2 +-
src/visualisers/Wind.cc | 4 +-
src/visualisers/WindPlotting.h | 4 +-
src/web/CMakeLists.txt | 1 +
src/web/GeoJSon.cc | 135 +
src/{decoders/BoxPlotDecoder.h => web/GeoJSon.h} | 73 +-
src/web/MagJSon.cc | 54 +-
src/web/MagJSon.h | 11 +
src/web/ObsJSon.cc | 8 +-
src/web/ObsJSon.h | 2 +-
src/web/WrepJSon.cc | 99 +-
src/web/WrepJSon.h | 9 +-
test/CMakeLists.txt | 160 +-
test/Testing/Temporary/CTestCostData.txt | 1 -
tools/xml2cc_new.pl | 5 +-
tools/xml2mv.pl | 3 +
335 files changed, 20546 insertions(+), 9442 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 02caae6..f40659d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,29 +33,90 @@ set(INSTALL_INCLUDE_DIR include/magics CACHE PATH "Magics installation directory
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../ecbuild/cmake")
-include( ecbuild_system )
+include( ecbuild_system NO_POLICY_SCOPE )
-ecbuild_requires_macro_version( 1.2 )
+ecbuild_requires_macro_version( 1.9 )
###############################################################################
# some variables of this project
-option( ENABLE_GRIB "enable grib support" ON )
-option( ENABLE_NETCDF "enable netcdf support" ON )
+ecbuild_use_package(PROJECT grib_api VERSION 1.12.3 REQUIRED)
+# grib_api is required for now
+set( HAVE_GRIB 1 )
+
+ecbuild_add_option( FEATURE BUFR
+ DEFAULT ON
+ DESCRIPTION "BUFR support"
+ REQUIRED_PACKAGES "PROJECT libemos VERSION 4.0.5" )
+
+ecbuild_add_option( FEATURE ODB
+ DEFAULT ON
+ DESCRIPTION "ODB support"
+ REQUIRED_PACKAGES
+ "PROJECT odb_api VERSION 0.10.2"
+ "PROJECT eckit VERSION 0.9.0" )
+
+ecbuild_add_option( FEATURE CAIRO
+ DEFAULT ON
+ DESCRIPTION "cairo support[png/jpeg]"
+ REQUIRED_PACKAGES PangoCairo )
+
+ecbuild_add_option( FEATURE GEOTIFF
+ DEFAULT OFF
+ DESCRIPTION "geotiff support [implies cairo]"
+ CONDITION HAVE_CAIRO
+ REQUIRED_PACKAGES GeoTIFF )
+
+ecbuild_add_option( FEATURE NETCDF
+ DEFAULT ON
+ DESCRIPTION "enable netcdf support"
+ REQUIRED_PACKAGES "NetCDF 4 COMPONENTS C CXX" )
+
+ecbuild_add_option( FEATURE SPOT
+ DEFAULT OFF
+ DESCRIPTION "enable spot support"
+ REQUIRED_PACKAGES "PROJECT spot" )
+
+ecbuild_add_option( FEATURE PYTHON
+ DEFAULT ON
+ DESCRIPTION "enable python interface"
+ REQUIRED_PACKAGES Python SWIG NumPy )
+
+if( HAVE_PYTHON )
+ include(UseSWIG)
+endif()
+
+ecbuild_add_option( FEATURE FORTRAN
+ DEFAULT ON
+ DESCRIPTION "enable Fortran interface" )
+
+if( HAVE_FORTRAN )
+ ecbuild_enable_fortran( REQUIRED )
+endif()
-option( ENABLE_ODB "enable odb" OFF )
-option( ENABLE_BUFR "enable bufr support" OFF )
-option( ENABLE_SPOT "enable spot support" OFF )
-option( ENABLE_CAIRO "enable cairo support[png/jpeg]" OFF )
-option( ENABLE_GEOTIFF "enable geotiff support [implies cairo]" OFF )
+ecbuild_add_option( FEATURE METVIEW
+ DEFAULT OFF
+ DESCRIPTION "enable Metview interface" )
-option( ENABLE_PYTHON "enable python interface" ON )
-option( ENABLE_FORTRAN "enable fortran interface" ON )
+ecbuild_add_option( FEATURE METVIEW_NO_QT
+ DEFAULT OFF
+ DESCRIPTION "enable Metview interface without Qt" )
-option( ENABLE_METVIEW "enable Metview interface" OFF )
-option( ENABLE_METVIEW_NO_QT "enable Metview interface without Qt" OFF )
+ecbuild_add_option( FEATURE QT5
+ DEFAULT OFF
+ DESCRIPTION "use Qt5 instead of version 4" )
-option( ENABLE_STATIC_LIBRARY "Internal Build static Library" OFF )
+ecbuild_add_option( FEATURE PNG
+ DESCRIPTION "support for PNG decoding/encoding"
+ DEFAULT ON
+ REQUIRED_PACKAGES PNG
+)
+
+if( HAVE_PNG )
+ add_definitions( ${PNG_DEFINITIONS} )
+endif()
+
+option( BUILD_SHARED_LIBS "Set to BOTH to build static library in addition to shared" ON )
option( ENABLE_REGRESSION "Internal use only: enable regression test" OFF )
option( ENABLE_REGRESSION_UPLOAD "Internal use only : enable upload of reference image" OFF )
@@ -65,7 +126,7 @@ set( MAGICS_SITE "ecmwf" )
set( MAGICS_INSTALL_PATH ${CMAKE_INSTALL_PREFIX} )
# Regression definitions
-set( MAGICS_REFERENCE_VERSIONS "2.24.5" )
+set( MAGICS_REFERENCE_VERSIONS "2.26.0" )
set( MAGICS_HTML_ROOT "${CMAKE_BINARY_DIR}/regression/html")
file(MAKE_DIRECTORY ${MAGICS_HTML_ROOT} )
@@ -76,149 +137,48 @@ set( MAG_PYTHON_PATH ${CMAKE_BINARY_DIR}/python )
# ecbuild_use_package( PROJECT eckit VERSION 0.3 REQUIRED )
-### fortran
-
-if( ENABLE_FORTRAN )
- ecbuild_enable_fortran( REQUIRED )
-endif()
-
-### python
-
-if( ENABLE_PYTHON )
- ecbuild_find_python( REQUIRED )
-
- debug_var( PYTHON_INCLUDE_DIRS )
- debug_var( PYTHON_LIBRARIES )
-
- if( NOT PYTHON_INCLUDE_DIRS OR NOT PYTHON_LIBRARIES )
- message( FATAL_ERROR "Couldn't find Python libraries" )
- endif()
-
- find_package( SWIG REQUIRED )
- find_package( NumPy REQUIRED )
-endif()
-if( SWIG_FOUND )
- include(UseSWIG)
-endif()
-
-### grib
#cmake_add_cxx_flags("-gdwarf-2")
-
-set( grib no )
-if( ENABLE_GRIB )
- ecbuild_use_package( PROJECT grib_api VERSION 1.9 REQUIRED)
-endif()
-if( GRIB_API_FOUND )
- set( MAGICS_GRIB 1 )
- set( grib yes )
-endif()
-
-### netcdf
-
-set( netcdf no )
-# set( PREFER_NETCDF4 1)
-# set( NETCDF_CXX 1 )
-if ( ENABLE_NETCDF )
- find_package( NetCDF 4 COMPONENTS C CXX REQUIRED)
-endif()
-if ( NETCDF_FOUND )
- list( APPEND MAGICS_TPLS NetCDF )
- set(MAGICS_NETCDF 1)
- set( netcdf yes)
-endif()
-
-### odb
-
-set( odb no )
-if( ENABLE_ODB )
- ecbuild_use_package( PROJECT odb_api VERSION 0.10.2 REQUIRED)
-endif()
-if( ODB_API_FOUND )
-
- get_filename_component( odb_api_install_dir ${ODB_API_CMAKE_DIR}/../../../lib ABSOLUTE )
- get_filename_component( eckit_install_dir ${ECKIT_CMAKE_DIR}/../../../lib ABSOLUTE )
-
- set( MAGICS_ODB 1 )
- set( odb yes)
-
- # does this version use eckit?
- list(FIND ODB_API_LIBRARIES eckit ODB_ECKIT_INDEX)
-
- if (NOT ODB_ECKIT_INDEX EQUAL -1) # is an eckit version
- add_definitions(-DODB_ECKIT)
- endif()
-
-endif()
-
-### spot
-
-set( spot no )
-if( ENABLE_SPOT )
- ecbuild_use_package( PROJECT spot REQUIRED)
- if( SPOT_FOUND )
- set (MAGICS_SPOT 1)
- set ( spot yes)
- endif()
-else()
-endif()
-
-### bufr
-
-set( bufr no )
-if( ENABLE_BUFR )
- find_package( EMOS REQUIRED )
-endif()
-if( EMOS_FOUND )
- set( MAGICS_BUFR 1 )
- set( bufr yes)
-endif()
-
-
-### cairo
-
-set( cairo no )
-if( ENABLE_CAIRO )
- find_package( PangoCairo REQUIRED )
-else()
- find_package( PangoCairo )
-endif()
-
-if( PANGOCAIRO_FOUND )
- set( MAGICS_CAIRO 1 )
- set( cairo yes )
- if( ENABLE_GEOTIFF )
- find_package( GeoTIFF REQUIRED )
- if( GEOTIFF_FOUND )
- set( MAGICS_GEOTIFF 1 )
- endif()
- endif()
-endif()
-
+cmake_add_c_flags("-std=c99")
### Metview and Qt
-if(ENABLE_METVIEW AND ENABLE_METVIEW_NO_QT)
- message(FATAL_ERROR "Do not set both ENABLE_METVIEW and ENABLE_METVIEW_NO_QT - only set one. You may have to remove your CMakeCache.txt to clear these settings.")
+if(HAVE_METVIEW AND HAVE_METVIEW_NO_QT)
+ message(FATAL_ERROR "Do not set both HAVE_METVIEW and HAVE_METVIEW_NO_QT - only set one. You may have to remove your CMakeCache.txt to clear these settings.")
endif()
set( qt no )
-set( qtlib no )
set( metview no )
-if( ENABLE_METVIEW_NO_QT )
+if( HAVE_METVIEW_NO_QT )
set( metview yes )
unset(MAGICS_ONLY)
endif()
-if( ENABLE_METVIEW )
+if( HAVE_METVIEW )
set ( metview yes)
+ message(STATUS "TESTING for Metview ...")
unset(MAGICS_ONLY)
+
+ if( HAVE_QT5 )
+ find_package(Qt5Widgets REQUIRED)
+ if( Qt5Widgets_FOUND )
+ message(STATUS "Qt5 was found ... ${Qt5Widgets_VERSION_STRING}")
+ include_directories(${Qt5Widgets_INCLUDE_DIRS})
+ set( MAGICS_QT 1)
+ set( MAGICS_QT5 1)
+ set( qt yes)
+ add_definitions( -DMAGICS_QT5 )
+ else()
+ message(FATAL_ERROR "Qt5 was NOT found ...")
+ endif()
+ else()
find_package(Qt4 4.4.3 REQUIRED QtCore QtGui QtXml )
if( QT_FOUND )
include( ${QT_USE_FILE} )
set( MAGICS_QT 1)
set( qt yes)
endif()
+ endif()
endif()
ecbuild_declare_project()
@@ -238,90 +198,87 @@ find_package( Boost 1.49.0 REQUIRED)
find_package( Proj4 REQUIRED )
find_package( EXPAT REQUIRED )
-
-install( FILES ${CMAKE_CURRENT_BINARY_DIR}/magics-config
- DESTINATION ${INSTALL_BIN_DIR}
- PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
- OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
-
-
###############################################################################
# contents
-set( MAGICS_TPLS grib_api spot odb_api EXPAT NetCDF PangoCairo Proj4 EMOS)
+set( MAGICS_TPLS grib_api spot EXPAT NetCDF PangoCairo PNG Proj4 libemos )
+
set( MAGICS_INCLUDE_DIRS
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_BINARY_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/src/common
- ${CMAKE_CURRENT_BINARY_DIR}/src/params
- ${CMAKE_CURRENT_BINARY_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/src/common
- ${CMAKE_CURRENT_SOURCE_DIR}/src/basic
- ${CMAKE_CURRENT_SOURCE_DIR}/src/web
- ${CMAKE_CURRENT_SOURCE_DIR}/src/visualisers
- ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers
- ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers/MgQ
- ${CMAKE_CURRENT_SOURCE_DIR}/src/eckit_readers
- ${CMAKE_CURRENT_SOURCE_DIR}/src/decoders
- ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib
- ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib/kernel
- ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib/utils
- ${Boost_INCLUDE_DIRS} )
-
-if( MAGICS_ODB )
- list( APPEND MAGICS_INCLUDE_DIRS
- ${CMAKE_CURRENT_SOURCE_DIR}/src/oda
- ${ODB_API_INCLUDE_DIRS}/../eclib
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_BINARY_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/common
+ ${CMAKE_CURRENT_BINARY_DIR}/src/params
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/common
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/basic
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/web
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/visualisers
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers/MgQ
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/eckit_readers
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/decoders
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib/kernel
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/terralib/utils
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/libMagWrapper
+ ${Boost_INCLUDE_DIRS}
+ ${PANGOCAIRO_INCLUDE_DIRS} )
+
+if( HAVE_ODB )
+ list( APPEND MAGICS_TPLS odb_api )
+ list( APPEND MAGICS_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/oda
+ ${ODB_API_INCLUDE_DIRS}
+ ${ECKIT_INCLUDE_DIRS} )
endif()
set( MAGICS_LIBRARIES MagPlus )
foreach( _tpl ${MAGICS_TPLS} )
string( TOUPPER ${_tpl} TPL )
+ if( NOT ${TPL} STREQUAL "LIBEMOS" ) # don't add libemos definitions
list( APPEND MAGICS_EXTRA_DEFINITIONS ${${TPL}_DEFINITIONS} )
+ endif()
list( APPEND MAGICS_EXTRA_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS} )
list( APPEND MAGICS_EXTRA_LIBRARIES ${${TPL}_LIBRARIES} )
endforeach()
-if( MAGICS_BUFR )
+if( HAVE_BUFR )
list( APPEND MAGICS_EXTRA_DEFINITIONS fortfloat=double fortint=int )
+ ecbuild_find_fortranlibs()
+ list( APPEND MAGICS_EXTRA_LIBRARIES ${FORTRAN_LIBRARIES} )
endif()
if( WITH_QT_DEBUG )
list( APPEND MAGICS_EXTRA_DEFINITIONS QT_NO_DEBUG_OUTPUT )
endif()
if( MAGICS_QT )
+ if( MAGICS_QT5 )
+ list( APPEND MAGICS_EXTRA_INCLUDE_DIRS ${Qt5Widgets_INCLUDE_DIR} )
+ list( APPEND MAGICS_EXTRA_LIBRARIES ${Qt5Widgets_LIBRARIES} )
+ else()
list( APPEND MAGICS_EXTRA_INCLUDE_DIRS ${QT_INCLUDE_DIR} )
list( APPEND MAGICS_EXTRA_LIBRARIES ${QT_LIBRARIES} )
endif()
+endif()
-if( MAGICS_GEOTIFF )
+if( HAVE_GEOTIFF )
list( APPEND MAGICS_EXTRA_INCLUDE_DIRS ${GEOTIFF_INCLUDE_DIR} )
list( APPEND MAGICS_EXTRA_LIBRARIES ${GEOTIFF_LIBRARY} )
- list( APPEND MAGICS_EXTRA_DEFINITIONS MAGICS_GEOTIFF )
+ list( APPEND MAGICS_EXTRA_DEFINITIONS HAVE_GEOTIFF )
endif()
list( APPEND MAGICS_EXTRA_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} )
-message(STATUS "MAGICS_EXTRA_DEFINITIONS => ${MAGICS_EXTRA_DEFINITIONS}")
-message(STATUS "MAGICS_EXTRA_INCLUDE_DIRS => ${MAGICS_EXTRA_INCLUDE_DIRS}")
-message(STATUS "MAGICS_EXTRA_LIBRARIES => ${MAGICS_EXTRA_LIBRARIES}")
-
-
+ecbuild_debug("MAGICS_EXTRA_DEFINITIONS => ${MAGICS_EXTRA_DEFINITIONS}")
+ecbuild_debug("MAGICS_EXTRA_INCLUDE_DIRS => ${MAGICS_EXTRA_INCLUDE_DIRS}")
+ecbuild_debug("MAGICS_EXTRA_LIBRARIES => ${MAGICS_EXTRA_LIBRARIES}")
# set_directory_properties( PROPERTIES COMPILE_DEFINITIONS "${ECKIT_DEFINITIONS}" )
get_directory_property( MAGICS_DEFINITIONS COMPILE_DEFINITIONS )
include_directories( ${MAGICS_INCLUDE_DIRS} ${MAGICS_EXTRA_INCLUDE_DIRS} )
-set( __magics_inc_tmp ${MAGICS_EXTRA_INCLUDE_DIRS} )
-set(MAGICS_EXTRA_INCLUDES "")
-
-foreach( inc ${__magics_inc_tmp} )
- set(MAGICS_EXTRA_INCLUDES "${MAGICS_EXTRA_INCLUDES} -I${inc}" )
-endforeach()
-
# scripts
add_subdirectory( tools )
@@ -348,88 +305,29 @@ ecbuild_add_resources( TARGET old_src DONT_PACK_DIRS src/MvObs src/libTable src/
ecbuild_add_resources( TARGET bamboo DONT_PACK_DIRS bamboo)
ecbuild_add_resources( TARGET old_ressources
DONT_PACK_DIRS tools/versioncmp
- tools/regression
- regression
- docs
- toolsjs
- test/old
- tools/xml
- tools/use_scripts
- tools/versioncmp_folders)
+ tools/regression
+ regression
+ docs
+ toolsjs
+ test/old
+ tools/xml
+ tools/use_scripts
+ tools/versioncmp_folders)
ecbuild_add_resources( TARGET internal
DONT_PACK configure.lxab
- configure.local
- configure.ecgb
- configure.ecmwf
- )
-
-
-set( __magics_tmp ${MAGICS_EXTRA_LIBRARIES} )
-
-list(REMOVE_ITEM __magics_tmp debug )
-list(REMOVE_ITEM __magics_tmp optimized )
-if( ODB_API_FOUND )
- list(REMOVE_ITEM __magics_tmp Odb)
- list(REMOVE_ITEM __magics_tmp eckit)
- list(REMOVE_ITEM __magics_tmp eckit_web)
- list(REMOVE_ITEM __magics_tmp eckit_geometry)
-endif()
-
-set(MAGICS_EXTRA_LIBS "")
-
-foreach( lib ${__magics_tmp} )
- if( lib MATCHES "^/.*" )
-# Need to split -L/path and -l libd
-
- get_filename_component(ext ${lib} EXT)
- if ( ${ext} MATCHES ${CMAKE_SHARED_LIBRARY_SUFFIX} )
-
- get_filename_component(path ${lib} PATH)
-
- list( APPEND RPATH "-Wl,-rpath,${path}")
- endif()
-
- else()
- if( NOT lib MATCHES "^-l.*" )
- set( lib "-l${lib}" )
- endif()
- endif()
-
- set(MAGICS_EXTRA_LIBS "${MAGICS_EXTRA_LIBS} ${lib}" )
-endforeach()
-
-
-set(MAGICS_RPATH " -Wl,-rpath,${CMAKE_INSTALL_PREFIX}/lib" )
-
-if( ODB_API_FOUND )
+ configure.local
+ configure.ecgb
+ configure.ecmwf
+)
- set(MAGICS_EXTRA_LIBS "${MAGICS_EXTRA_LIBS} -L${odb_api_install_dir} -lOdb")
- set(MAGICS_EXTRA_LIBS "${MAGICS_EXTRA_LIBS} -L${eckit_install_dir} -leckit")
- set(MAGICS_EXTRA_LIBS "${MAGICS_EXTRA_LIBS} -L${eckit_install_dir} -leckit_web")
- set(MAGICS_EXTRA_LIBS "${MAGICS_EXTRA_LIBS} -L${eckit_install_dir} -leckit_geometry")
- set(MAGICS_RPATH "${MAGICS_RPATH} -Wl,-rpath,${eckit_install_dir}" )
- set(MAGICS_RPATH "${MAGICS_RPATH} -Wl,-rpath,${odb_api_install_dir}" )
-endif()
-
-
-
-
-list(REMOVE_DUPLICATES RPATH)
-
-foreach( path ${RPATH} )
- set(MAGICS_RPATH "${MAGICS_RPATH} ${path}" )
-endforeach()
-
-debug_var(MAGICS_RPATH)
-
-
-configure_file( magics-config.in magics-config @ONLY )
-# ecbuild/cmake is needed in the the distribution tar ball!
-
############################################################################################
# finalize
+set( MAGICS_DESCRIPTION "Multi-platform meteorological graphics library" )
+set( MAGICS_URL "https://software.ecmwf.int/wiki/display/MAGP/Magics" )
+ecbuild_pkgconfig()
+
ecbuild_install_project( NAME Magics )
ecbuild_print_summary()
diff --git a/INSTALL b/INSTALL
index 54caf7c..a98857f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,229 +1,8 @@
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
- This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
+With Magics 2.22 the installtion has changed to use CMake. This is inline
+with other software packages at ECMWF.
-Basic Installation
-==================
+For more deatils please consult the installation guide at
- These are generic installation instructions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system. If you're
- using `csh' on an old version of System V, you might need to type
- `sh ./configure' instead to prevent `csh' from trying to execute
- `configure' itself.
-
- Running `configure' takes awhile. While running, it prints some
- messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package.
-
- 4. Type `make install' to install the programs and any data files and
- documentation.
-
- 5. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
- If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory. After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
- By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc. You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
+ https://software.ecmwf.int/wiki/display/MAGP/Installation+Guide
diff --git a/NOTICE b/NOTICE
index 602bfdf..44d7270 100644
--- a/NOTICE
+++ b/NOTICE
@@ -202,3 +202,66 @@ use the software is given as comments in the source code.
Note that we (ECMWF) have made some small modifications to the code in order to allow
it to be used also for non-MSG satellite images.
+
+--------------------------------------------------------------
+
+libimagequant
+=============
+
+The quantization and dithering code in pngquant is lifted from Jef Poskanzer's
+'ppmquant', part of his wonderful PBMPLUS tool suite.
+
+Greg Roelofs hacked it into a (in his words) "slightly cheesy" 'pamquant' back
+in 1997 (see http://pobox.com/~newt/greg_rgba.html) and finally he ripped out
+the cheesy file-I/O parts and replaced them with nice PNG code in December
+2000. The PNG reading and writing code is a merged and slightly simplified
+version of readpng, readpng2, and writepng from his book "PNG: The Definitive
+Guide."
+In 2014 Greg has relicensed the code under the simplified BSD license.
+
+Note that both licenses are basically BSD-like; that is, use the code however
+you like, as long as you acknowledge its origins.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+pngquant.c:
+
+ © 1989, 1991 by Jef Poskanzer.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation. This software is provided "as is" without express or
+ implied warranty.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+pngquant.c and rwpng.c/h:
+
+ © 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
+ © 2009-2014 by Kornel Lesiński.
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/VERSION.cmake b/VERSION.cmake
index ff5034c..17915ac 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -1,9 +1,10 @@
-set ( metabuilder_version 2.24.7 )
-set ( _version 2.24.7 )
+
+set ( metabuilder_version 2.26.2 )
+set ( _version 2.26.2 )
if ( MAGICS_BUILD )
set( ${PROJECT_NAME}_VERSION_STR "${_version}-${MAGICS_BUILD}" )
else ()
set( ${PROJECT_NAME}_VERSION_STR ${_version})
endif()
-set( BRANCH_NAME ${${PROJECT_NAME}_VERSION_STR} )
+set( BRANCH_NAME ${${PROJECT_NAME}_VERSION_STR} )
diff --git a/apps/MagMLInterpretor/CMakeLists.txt b/apps/MagMLInterpretor/CMakeLists.txt
index 1b97e35..ac3fb54 100644
--- a/apps/MagMLInterpretor/CMakeLists.txt
+++ b/apps/MagMLInterpretor/CMakeLists.txt
@@ -19,7 +19,7 @@ ecbuild_add_executable( TARGET magjsonx
DEFINITIONS
${MAGICS_EXTRA_DEFINITIONS}
LIBS
- MagPlusShared ${MAGICS_EXTRA_LIBRARIES}
+ MagPlus ${MAGICS_EXTRA_LIBRARIES}
)
ecbuild_add_executable( TARGET magmlx
@@ -28,5 +28,5 @@ ecbuild_add_executable( TARGET magmlx
DEFINITIONS
${MAGICS_EXTRA_DEFINITIONS}
LIBS
- MagPlusShared ${MAGICS_EXTRA_LIBRARIES}
+ MagPlus ${MAGICS_EXTRA_LIBRARIES}
)
diff --git a/apps/metgram/CMakeLists.txt b/apps/metgram/CMakeLists.txt
index f730430..19aad68 100644
--- a/apps/metgram/CMakeLists.txt
+++ b/apps/metgram/CMakeLists.txt
@@ -1,8 +1,11 @@
-
-
-
+# Copy metgram executable to the build tree
+configure_file( metgram metgram COPYONLY )
configure_file( metgram-script.in metgram.sh @ONLY )
+# Set metgram script path for use by dependencies in a bundle
+set( MAGICS_METEOGRAM_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/metgram
+ CACHE FILEPATH "Path to metgram script" )
+
install ( DIRECTORY templates DESTINATION ${INSTALL_DATA_DIR}/.. FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
@@ -18,7 +21,5 @@ ecbuild_add_executable( TARGET metgramx
DEFINITIONS
${MAGICS_EXTRA_DEFINITIONS}
LIBS
- MagPlusShared ${MAGICS_EXTRA_LIBRARIES}
+ MagPlus ${MAGICS_EXTRA_LIBRARIES}
)
-
-
diff --git a/apps/metgram/metgram.py b/apps/metgram/metgram.py
new file mode 100755
index 0000000..c758e60
--- /dev/null
+++ b/apps/metgram/metgram.py
@@ -0,0 +1,130 @@
+
+import xml.sax
+import requests
+import json
+import sys, getopt
+
+epsgrams = {
+ "15_days" : "classical_15d",
+ "15_days_with_clim" : "classical_15d_with_climate",
+ "10_days" : "classical_10d",
+ "10_days_wave": "classical_wave",
+ "10_days_plumes" : "classical_plume",
+
+}
+
+class MetgramHandler( xml.sax.ContentHandler ):
+ def __init__(self):
+ self.CurrentData = ""
+ self.type = ""
+ self.date = ""
+ self.expver = ""
+ self.stations = []
+
+
+ # Call when an element starts
+ def startElement(self, tag, attributes):
+ self.CurrentData = tag
+ if tag == "eps":
+ self.type = attributes["template"]
+ self.date = attributes.get("date", "")
+ self.time = attributes.get("time", "")
+ if ( self.time != "") :
+ self.time = self.time[:2]
+ self.expver = attributes.get("expver", "0001")
+ self.stations = []
+ if self.date == "latest":
+ self.date = ""
+ else:
+ self.date = "%s%s" % (self.date, self.time)
+
+
+ if tag == "station":
+
+ request = {
+ "station_name" : attributes["name"],
+ "lat" : attributes["latitude"],
+ "lon" : attributes["longitude"],
+ "token" : "metview",
+ "expver" : self.expver,
+ "epsgram" : epsgrams[self.type]
+ }
+ if attributes.has_key("height") :
+ request["altitude"] = attributes["height"],
+
+ if self.date != "" :
+ request["time"] = self.date
+
+ if attributes.has_key("pngfile") :
+ request["format"] = "png"
+ output = attributes["pngfile"]
+ if attributes.has_key("psfile") :
+ request["format"] = "ps"
+ output = attributes["psfile"]
+ if attributes.has_key("pdffile") :
+ request["format"] = "pdf"
+ output = attributes["pdffile"]
+ self.stations.append({"request" : request,
+ "output": output}
+ )
+
+
+
+ # Call when an elements ends
+ def endElement(self, tag):
+ if tag == "eps":
+
+
+ self.execute()
+
+
+
+ # Call when a character is read
+ def characters(self, content):
+ pass
+
+ def execute(self):
+ url = "https://apps.ecmwf.int/plots/product-download/web/classical_meteogram"
+ for station in self.stations :
+ request = station["request"]
+ request["token"] = "metview"
+ request["email"] = "Web.Administrator at ecmwf.int"
+ request = requests.get(url, params = request,
+ proxies = { "http": "http://proxy.ecmwf.int:3333/" })
+ print request.url
+ if request.status_code == 200 :
+ out = open(station["output"], "w")
+ out.write(request.content)
+ out.close()
+ print "Result saved in %s" % (station["output"], )
+ else :
+ print "No Result -->Error %d" % (request.status_code)
+ self.stations = []
+
+
+def main(argv):
+ try:
+ opts, args = getopt.getopt(argv,"hi:",["input="])
+ except getopt.GetoptError:
+ print 'metgram.py -i <inputfile> '
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt == '-h':
+ print 'metgram.py -i <inputfile> '
+ sys.exit()
+ elif opt in ("-i", "--input"):
+ input = arg
+
+ # create an XMLReader
+ parser = xml.sax.make_parser()
+ # turn off namepsaces
+ parser.setFeature(xml.sax.handler.feature_namespaces, 0)
+
+ # override the default ContextHandler
+ Handler = MetgramHandler()
+ parser.setContentHandler( Handler )
+
+ parser.parse(input)
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt
new file mode 100644
index 0000000..24a12cf
--- /dev/null
+++ b/bin/CMakeLists.txt
@@ -0,0 +1,3 @@
+if( ENABLE_INSTALL )
+ install( PROGRAMS ecbuild DESTINATION ${INSTALL_BIN_DIR} )
+endif()
diff --git a/bin/ecbuild b/bin/ecbuild
new file mode 100755
index 0000000..8a271dc
--- /dev/null
+++ b/bin/ecbuild
@@ -0,0 +1,422 @@
+#!/bin/bash
+
+set -eua
+
+CMAKE_MIN_REQUIRED=2.8.10
+CMAKE_BUILD_VERSION=3.2.3
+
+usage()
+{
+ echo "Usage: ecbuild [--help] [--version]"
+ exit $1
+}
+
+help()
+{
+ cat <<EOF
+USAGE:
+
+ ecbuild [--help] [--version] [--toolchains]
+ ecbuild [option...] [--] [cmake-argument...] <path-to-source>
+ ecbuild [option...] [--] [cmake-argument...] <path-to-existing-build>
+
+DESCRIPTION:
+
+ ecbuild is a build system based on CMake, but providing a lot of macro's
+ to make it easier to work with. Upon execution,
+ the equivalent cmake command is printed.
+
+ ecbuild/cmake must be called from an out-of-source build directory and
+ forbids in-source builds.
+
+SYNOPSIS:
+
+ --help Display this help
+ --version Display ecbuild version
+ --toolchains Display list of pre-installed toolchains (see below)
+
+
+Available values for "option":
+
+ --cmakebin=<path>
+ Set which cmake binary to use. Default is 'cmake'
+
+ --prefix=<prefix>
+ Set the install path to <prefix>.
+ Equivalent to cmake argument "-DCMAKE_INSTALL_PREFIX=<prefix>"
+
+ --build=<build-type>
+ Set the build-type to <build-type>.
+ Equivalent to cmake argument "-DCMAKE_BUILD_TYPE=<build-type>"
+ <build-type> can be any of:
+ - debug : Lowest optimization level, useful for debugging
+ - release : Highest optimization level, for best performance
+ - bit : Highest optimization level while staying bit-reproducible
+ - ...others depending on project
+
+ --log=<log-level>
+ Set the ecbuild log-level
+ Equivalent to "-DECBUILD_LOG_LEVEL=<log-level>"
+ <log-level> can be any of:
+ - DEBUG
+ - INFO
+ - WARN
+ - ERROR
+ - CRITICAL
+ - OFF
+ Every choice outputs also the log-levels listed below itself
+
+ --static
+ Build static libraries.
+ Equivalent to "-DBUILD_SHARED_LIBS=OFF"
+
+ --dynamic
+ Build dynamic libraries (usually the default).
+ Equivalent to "-DBUILD_SHARED_LIBS=ON"
+
+ --shared (same option as --dynamic)
+ Build dynamic libraries (usually the default).
+ Equivalent to "-DBUILD_SHARED_LIBS=ON"
+
+ --toolchain=<toolchain>
+ Use a platform specific toolchain, containing settings such
+ as compilation flags, locations of commonly used dependencies.
+ <toolchain> can be the path to a custom toolchain file, or a
+ pre-installed toolchain provided with ecbuild. For a list of
+ pre-installed toolchains, run "ecbuild --toolchains".
+ Equivalent to cmake argument "-DCMAKE_TOOLCHAIN_FILE=<toolchain-file>"
+
+ --cache=<ecbuild-cache-file> (advanced)
+ A file called "ecbuild-cache.cmake" is generated during configuration.
+ This file can be moved to a safe location, and specified for future
+ builds to speed up checking of compiler/platform capabilities. Note
+ that this is only accelerating fresh builds, as cmake internally
+ caches also. Therefore this option is *not* recommended.
+
+ --build-cmake
+ Automatically download and build CMake version $CMAKE_BUILD_VERSION if the CMake
+ version found does not meet the minimum requirements (version $CMAKE_MIN_REQUIRED
+ is required). Requires an internet connection and may take a while.
+
+ --dryrun
+ Don't actually execute the cmake call, just print what would have
+ been executed.
+
+
+Available values for "cmake-argument":
+
+ Any value that can be usually passed to cmake to (re)configure the build.
+ Typically these values start with "-D".
+ example: -DENABLE_TESTS=ON -DENABLE_MPI=OFF -DECKIT_PATH=...
+
+ They can be explicitly separated from [option...] with a "--", for the case
+ there is a conflicting option with the "cmake" executable, and the latter's
+ option is requested.
+
+------------------------------------------------------------------------
+
+NOTE: When reconfiguring a build, it is only necessary to change the relevant
+options, as everything stays cached. For example:
+ > ecbuild --prefix=PREFIX .
+ > ecbuild -DENABLE_TESTS=ON .
+
+------------------------------------------------------------------------
+
+Compiling:
+
+ To compile the project with <N> threads:
+ > make -j<N>
+
+ To get verbose compilation/linking output:
+ > make VERBOSE=1
+
+Testing:
+
+ To run the project's tests
+ > ctest
+
+ Also check the ctest manual/help for more options on running tests
+
+Installing:
+
+ To install the project in location PREFIX with
+ "--prefix=PREFIX" or
+ "-DCMAKE_INSTALL_PREFIX=PREFIX"
+ > make install
+
+------------------------------------------------------------------------
+ECMWF"
+
+EOF
+ exit $1
+}
+
+
+INSTALL_DIR="$( dirname $( readlink -e "${BASH_SOURCE[0]}" ) )"
+ECBUILD_MODULE_PATH=""
+# If there is a directory share/ecbuild/cmake relative to the parent directory
+# (as in an install tree), add it to CMAKE_MODULE_PATH
+if [ -d $INSTALL_DIR/../share/ecbuild/cmake ]; then
+ ECBUILD_MODULE_PATH="$( readlink -e $INSTALL_DIR/../share/ecbuild/cmake )"
+fi
+# If there is a cmake subdirectory relative to the script directory (as in a
+# tarball), add it to CMAKE_MODULE_PATH
+if [ -d $INSTALL_DIR/../cmake ]; then
+ ECBUILD_MODULE_PATH="$( readlink -e $INSTALL_DIR/../cmake );$ECBUILD_MODULE_PATH"
+fi
+if [ -n "$ECBUILD_MODULE_PATH" ]; then
+ ADD_ECBUILD_OPTIONS="-DCMAKE_MODULE_PATH=$ECBUILD_MODULE_PATH"
+fi
+
+if [ -d $INSTALL_DIR/../share/ecbuild/toolchains ]; then
+ ECBUILD_TOOLCHAIN_DIR="$( readlink -e $INSTALL_DIR/../share/ecbuild/toolchains )"
+elif [ -d $INSTALL_DIR/share/ecbuild/toolchains ]; then
+ ECBUILD_TOOLCHAIN_DIR="$( readlink -e $INSTALL_DIR/share/ecbuild/toolchains )"
+fi
+
+version()
+{
+ ecbuild_version=$(cat ${ECBUILD_MODULE_PATH}/VERSION.cmake | grep ECBUILD_VERSION_STR | perl -p -e 's/.*([\d]\.[\d]\.[\d]).*/\1/' )
+ echo "ecbuild version ${ecbuild_version}"
+ command -v cmake >/dev/null 2>&1 || { exit 0; }
+ cmake --version | head -1
+ exit 0
+}
+
+log()
+{
+ log_level=$(sed 's/.*/\U&/' <<< "$1")
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DECBUILD_LOG_LEVEL=${log_level}"
+}
+
+toolchains()
+{
+ if [ -d $ECBUILD_TOOLCHAIN_DIR ]; then
+ cd $ECBUILD_TOOLCHAIN_DIR
+ echo "Available toolchains:"
+ ls | while read fname
+ do
+ echo " - ${fname%%.*}"
+ done
+ exit 0
+ else
+ echo "No toolchains available."
+ exit 1
+ fi
+}
+
+prefix()
+{
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_INSTALL_PREFIX=$(readlink -m ${1/#\~\//$HOME\/})"
+}
+
+toolchain()
+{
+ arg=$1
+ if [ -f $arg ]; then
+ toolchain_file=$arg
+ else
+ if [ -f $ECBUILD_TOOLCHAIN_DIR/$arg.cmake ]; then
+ toolchain_file=$ECBUILD_TOOLCHAIN_DIR/$arg.cmake
+ fi
+ fi
+ if [ -z ${toolchain_file+x} ]; then
+ echo "Error:"
+ echo " Toolchain [$arg] is not valid: [$arg.cmake] cannot be"
+ echo " found in [$ECBUILD_TOOLCHAIN_DIR]"
+ exit 1
+ else
+ toolchain_file=$( readlink -e "$toolchain_file" )
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${toolchain_file}"
+ fi
+}
+
+cache()
+{
+ arg=$1
+ if [ -f $arg ]; then
+ cache_file=$( readlink -e "$arg" )
+ else
+ echo "Error:"
+ echo " Cache file [$arg] is not found or is not a file."
+ exit 1
+ fi
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DECBUILD_CACHE=${cache_file}"
+}
+
+if test $# -eq 0; then
+ usage 1
+fi
+
+while test $# -gt 0; do
+
+ # Split --option=value in $opt="--option" and $val="value"
+
+ opt=""
+ val=""
+
+ case "$1" in
+ --*=*)
+ opt=`echo "$1" | sed 's/=.*//'`
+ val=`echo "$1" | sed 's/--[_a-zA-Z0-9]*=//'`
+ ;;
+ --*)
+ opt=$1
+ ;;
+ # -D*)
+ # ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS $1"
+ # ;;
+ *)
+ break
+ ;;
+ esac
+
+ # echo "debug opt: $opt $val"
+
+ # Parse options
+ case "$opt" in
+ --help)
+ help 0
+ ;;
+ --version)
+ version
+ ;;
+ --dryrun)
+ dryrun="yes"
+ ;;
+ --toolchains)
+ toolchains
+ ;;
+ --cmakebin)
+ cmakebin="$val"
+ ;;
+ --prefix)
+ prefix $val
+ ;;
+ --build)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DCMAKE_BUILD_TYPE=$val"
+ ;;
+ --log)
+ log $val
+ ;;
+ --static)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=OFF"
+ ;;
+ --dynamic)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=ON"
+ ;;
+ --shared)
+ ADD_ECBUILD_OPTIONS="$ADD_ECBUILD_OPTIONS -DBUILD_SHARED_LIBS=ON"
+ ;;
+ --toolchain)
+ toolchain $val
+ ;;
+ --cache)
+ cache $val
+ ;;
+ --build-cmake)
+ build_cmake="yes"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ echo "unknown option: $opt"
+ usage 1
+ ;;
+ esac
+ shift
+done
+
+# If no arguments remain, set srcARG to "."
+if [ $# -eq 0 ]; then
+ srcARG="."
+fi
+
+src=${srcARG:=""}
+cmake=${cmakebin:=cmake}
+dryrun=${dryrun:=no}
+build_cmake=${build_cmake:=""}
+cmake_found=""
+cmake_version_sufficient=""
+
+
+# Check that version $1 satisfies $2
+# CMake versions have no more than 4 fields
+# (adapted from http://stackoverflow.com/a/25731924/396967)
+version_gte() {
+ [ "$2" = "$(echo -e "$1\n$2" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g | head -n1)" ]
+}
+
+# Check if the cmake version is sufficient
+check_cmake() {
+ # Check if cmake is available
+ if $(command -v $cmake >/dev/null 2>&1); then
+ cmake_found="yes"
+ cmake_version=$($cmake --version | head -n1 | awk '{ print $3 }')
+ echo "Found CMake version $cmake_version" >& 2
+ if version_gte $cmake_version $CMAKE_MIN_REQUIRED; then
+ cmake_version_sufficient="yes"
+ fi
+ fi
+}
+check_cmake
+# Use already built CMake if any
+if [[ ! $cmake_version_sufficient && -x bin/cmake ]]; then
+ echo "Using already built CMake in $PWD/bin/cmake" >&2
+ cmake=bin/cmake
+ check_cmake
+fi
+
+# Build CMake if requested and no sufficient version found
+if [[ ! $cmake_version_sufficient && $build_cmake ]]; then
+ echo "CMake version $CMAKE_MIN_REQUIRED is required but only $cmake_version was found." >&2
+ echo "Building CMake version ${CMAKE_BUILD_VERSION} ..." >&2
+ tarball=cmake-${CMAKE_BUILD_VERSION}.tar.gz
+ if [[ ! -r $tarball ]]; then
+ url=http://www.cmake.org/files/v${CMAKE_BUILD_VERSION:0:3}/$tarball
+ # -N Download only if the remote version of the file is newer
+ # --continue Continue an interrupted download
+ # -T 60 Time out a download attempt after 60 seconds
+ # -t 3 Only make 3 download attempts
+ wget -N --continue -T 60 -t 3 $url || {
+ echo "Failed to download CMake release $CMAKE_BUILD_VERSION." >&2
+ echo "Please download from $url" >&2
+ echo "and place $tarball in $PWD" >&2
+ exit 1
+ }
+ fi
+ tar xzf cmake-${CMAKE_BUILD_VERSION}.tar.gz
+ (
+ mkdir -p build_cmake
+ cd build_cmake
+ ../cmake-${CMAKE_BUILD_VERSION}/bootstrap --prefix=.. && make && make install
+ )
+ cmake=bin/cmake
+ check_cmake
+fi
+
+# Fail if we don't have a sufficient CMake
+if [[ ! $cmake_version_sufficient ]]; then
+ if [[ ! $cmake_found ]]; then
+ echo "CMake is required and cannot be found in the PATH." >&2
+ else
+ echo "CMake version $CMAKE_MIN_REQUIRED is required but only $cmake_version was found." >&2
+ fi
+ echo "" >&2
+ echo " Try 'module load cmake', specify a CMake binary with --cmakebin=/path/to/cmake" >&2
+ echo " or let ecbuild download and build CMake with the --build-cmake option." >&2
+ exit 1
+fi
+
+echo ""
+echo "$cmake ${ADD_ECBUILD_OPTIONS} $@ $src"
+echo ""
+
+if [ ${dryrun} == "yes" ]; then
+ echo "[DRYRUN] -- not executing"
+ exit 0
+fi
+
+$cmake ${ADD_ECBUILD_OPTIONS} "$@" $src
diff --git a/cmake/CheckFortranSourceCompiles.cmake b/cmake/CheckFortranSourceCompiles.cmake
index ad4b91f..4303315 100644
--- a/cmake/CheckFortranSourceCompiles.cmake
+++ b/cmake/CheckFortranSourceCompiles.cmake
@@ -29,7 +29,7 @@
macro(CHECK_FORTRAN_SOURCE_COMPILES SOURCE VAR)
-if("${VAR}" MATCHES "^${VAR}$")
+if( ${VAR} MATCHES "^${VAR}$" )
set(_FAIL_REGEX)
set(_key)
foreach(arg ${ARGN})
diff --git a/cmake/FindAEC.cmake b/cmake/FindAEC.cmake
index 70a63b1..28d086d 100644
--- a/cmake/FindAEC.cmake
+++ b/cmake/FindAEC.cmake
@@ -14,8 +14,6 @@
# AEC_INCLUDE_DIRS - The AEC include directories
# AEC_LIBRARIES - The libraries needed to use AEC
-ecbuild_add_extra_search_paths( aec )
-
if( DEFINED AEC_PATH )
find_path( AEC_INCLUDE_DIR szlib.h PATHS ${AEC_PATH}/include PATH_SUFFIXES aec NO_DEFAULT_PATH )
find_library( AEC_LIBRARY NAMES aec PATHS ${AEC_PATH}/lib PATH_SUFFIXES aec NO_DEFAULT_PATH )
diff --git a/cmake/FindArmadillo.cmake b/cmake/FindArmadillo.cmake
index ba14e2e..4183306 100644
--- a/cmake/FindArmadillo.cmake
+++ b/cmake/FindArmadillo.cmake
@@ -6,19 +6,28 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-ecbuild_add_extra_search_paths( armadillo )
-
-IF( NOT DEFINED ARMADILLO_PATH AND NOT "$ENV{ARMADILLO_PATH}" STREQUAL "" )
- SET( ARMADILLO_PATH "$ENV{ARMADILLO_PATH}" )
-ENDIF()
-
-if( DEFINED ARMADILLO_PATH )
- find_path(ARMADILLO_INCLUDE_DIR ARMADILLO.h PATHS ${ARMADILLO_PATH}/include PATH_SUFFIXES ARMADILLO NO_DEFAULT_PATH)
- find_library(ARMADILLO_LIBRARY ARMADILLO PATHS ${ARMADILLO_PATH}/lib PATH_SUFFIXES ARMADILLO NO_DEFAULT_PATH)
-endif()
-
+# - Try to find Armadillo
+# Once done this will define
+#
+# ARMADILLO_FOUND - system has Armadillo
+# ARMADILLO_INCLUDE_DIRS - the Armadillo include directory
+# ARMADILLO_LIBRARIES - the Armadillo library
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# ARMADILLO_PATH - prefix path of the Armadillo installation
+
+# Search with priority for ARMADILLO_PATH if given as CMake or env var
+find_path(ARMADILLO_INCLUDE_DIR armadillo
+ PATHS ${ARMADILLO_PATH} ENV ARMADILLO_PATH
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
find_path(ARMADILLO_INCLUDE_DIR armadillo PATH_SUFFIXES include )
-find_library( ARMADILLO_LIBRARY armadillo PATH_SUFFIXES lib )
+
+# Search with priority for ARMADILLO_PATH if given as CMake or env var
+find_library(ARMADILLO_LIBRARY armadillo
+ PATHS ${ARMADILLO_PATH} ENV ARMADILLO_PATH
+ PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH)
+find_library( ARMADILLO_LIBRARY armadillo PATH_SUFFIXES lib64 lib )
set( ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} )
set( ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR} )
diff --git a/cmake/FindEMOS.cmake b/cmake/FindEMOS.cmake
index 8472b0a..56ee334 100644
--- a/cmake/FindEMOS.cmake
+++ b/cmake/FindEMOS.cmake
@@ -12,8 +12,6 @@
# EMOS_INCLUDE_DIRS - The EMOS include directories
# EMOS_LIBRARIES - The libraries needed to use EMOS
-ecbuild_add_extra_search_paths( libemos )
-
if( NOT DEFINED EMOS_PATH AND DEFINED $ENV{EMOS_PATH} )
set( EMOS_PATH $ENV{EMOS_PATH} )
endif()
diff --git a/cmake/FindEcLib.cmake b/cmake/FindEcLib.cmake
deleted file mode 100644
index 5799c85..0000000
--- a/cmake/FindEcLib.cmake
+++ /dev/null
@@ -1,49 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find EcLib
-# Once done this will define
-# ECLIB_FOUND - System has ECLIB
-# ECLIB_INCLUDE_DIRS - The ECLIB include directories
-# ECLIB_LIBRARIES - The libraries needed to use ECLIB
-
-# skip if ECLIB is already found or if has is built inside
-
-if( NOT ECLIB_FOUND )
-
- # find external eclib
-
- set( _ENV_ECLIB_PATH "$ENV{ECLIB_PATH}" )
- if( NOT DEFINED ECLIB_PATH AND _ENV_ECLIB_PATH )
- set( ECLIB_PATH ${_ENV_ECLIB_PATH} )
- endif()
-
- if( DEFINED ECLIB_PATH )
- find_path(ECLIB_INCLUDE_DIR NAMES eclib_version.h PATHS ${ECLIB_PATH} ${ECLIB_PATH}/include PATH_SUFFIXES eclib NO_DEFAULT_PATH)
- find_library(ECLIB_LIBRARY NAMES Ec PATHS ${ECLIB_PATH} ${ECLIB_PATH}/lib PATH_SUFFIXES eclib NO_DEFAULT_PATH)
- endif()
-
- find_path(ECLIB_INCLUDE_DIR NAMES eclib_version.h PATH_SUFFIXES eclib )
- find_library( ECLIB_LIBRARY NAMES Ec PATH_SUFFIXES eclib )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECLIB_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(ECLIB DEFAULT_MSG
- ECLIB_LIBRARY ECLIB_INCLUDE_DIR )
-
- mark_as_advanced(ECLIB_INCLUDE_DIR ECLIB_LIBRARY )
-
- set( ECLIB_LIBRARIES ${ECLIB_LIBRARY} )
- set( ECLIB_INCLUDE_DIRS ${ECLIB_INCLUDE_DIR} )
-
- debug_var( ECLIB_LIBRARIES )
- debug_var( ECLIB_INCLUDE_DIRS )
-
-endif()
diff --git a/cmake/FindEcregrid.cmake b/cmake/FindEcregrid.cmake
deleted file mode 100644
index 3ddf732..0000000
--- a/cmake/FindEcregrid.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ECREGRID
-# Once done this will define
-# ECREGRID_FOUND - System has ECREGRID
-# ECREGRID_INCLUDE_DIRS - The ECREGRID include directories
-# ECREGRID_LIBRARIES - The libraries needed to use ECREGRID
-# ECREGRID_DEFINITIONS - Compiler switches required for using ECREGRID
-
-option( WITH_ECREGRID "try to find scin installation" ON )
-
-# skip if ECREGRID is already found or if has is built inside
-
-if( NOT ECREGRID_FOUND AND WITH_ECREGRID )
-
- if( NOT DEFINED ECREGRID_PATH AND NOT "$ENV{ECREGRID_PATH}" STREQUAL "" )
- list( APPEND ECREGRID_PATH "$ENV{ECREGRID_PATH}" )
- endif()
-
- if( DEFINED ECREGRID_PATH )
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/include PATH_SUFFIXES scin_api NO_DEFAULT_PATH )
- find_library(ECREGRID_LIBRARY NAMES scin PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/lib PATH_SUFFIXES scin NO_DEFAULT_PATH )
- endif()
-
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATH_SUFFIXES scin_api )
- find_library( ECREGRID_LIBRARY NAMES scin PATH_SUFFIXES scin )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECREGRID_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(Scin DEFAULT_MSG
- ECREGRID_LIBRARY ECREGRID_INCLUDE_DIR)
-
- if( ECREGRID_FOUND )
- set( ECREGRID_LIBRARIES ${ECREGRID_LIBRARY} )
- set( ECREGRID_INCLUDE_DIRS ${ECREGRID_INCLUDE_DIR} )
- endif()
-
- mark_as_advanced(ECREGRID_INCLUDE_DIR ECREGRID_LIBRARY )
-
-endif()
diff --git a/cmake/FindLibIFort.cmake b/cmake/FindLibIFort.cmake
new file mode 100644
index 0000000..e1d82ee
--- /dev/null
+++ b/cmake/FindLibIFort.cmake
@@ -0,0 +1,47 @@
+# © Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# date: July 2015
+# author: Florian Rathgeber
+
+###############################################################################
+
+# - Try to find Intel Fortran (ifort) runtime libraries libifcore and libifport
+# Once done this will define
+#
+# LIBIFORT_FOUND - system has Intel Fortran (ifort) runtime libraries
+# IFORT_LIBRARIES - the Intel Fortran (ifort) runtime libraries
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# INTEL_PATH - prefix path of the Intel installation
+#
+# Otherwise the libraries are assumed to be on LIBRARY_PATH or LD_LIBRARY_PATH
+
+# FIXME: might need to add further libraries in future, see
+# http://nf.nci.org.au/facilities/software/Compilers/Intel8/doc/f_ug1/files_32.htm
+
+# Search with priority for INTEL_PATH if given as CMake or env var
+find_library( IFORT_LIB_CORE ifcore PATHS ${INTEL_PATH} ENV INTEL_PATH
+ PATH_SUFFIXES lib/intel64 compiler/lib/intel64 NO_DEFAULT_PATH )
+find_library( IFORT_LIB_PORT ifport PATHS ${INTEL_PATH} ENV INTEL_PATH
+ PATH_SUFFIXES lib/intel64 compiler/lib/intel64 NO_DEFAULT_PATH )
+
+# Otherwise, search LIBRARY_PATH and LD_LIBRARY_PATH
+find_library( IFORT_LIB_CORE ifcore PATHS ENV LIBRARY_PATH LD_LIBRARY_PATH )
+find_library( IFORT_LIB_PORT ifport PATHS ENV LIBRARY_PATH LD_LIBRARY_PATH )
+
+mark_as_advanced( IFORT_LIB_CORE IFORT_LIB_PORT )
+
+if( IFORT_LIB_CORE AND IFORT_LIB_PORT )
+ set( IFORT_LIBRARIES ${IFORT_LIB_CORE} ${IFORT_LIB_PORT} )
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( LIBIFORT DEFAULT_MSG IFORT_LIBRARIES )
diff --git a/cmake/FindMKL.cmake b/cmake/FindMKL.cmake
new file mode 100644
index 0000000..fe182a4
--- /dev/null
+++ b/cmake/FindMKL.cmake
@@ -0,0 +1,77 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find MKL
+# Once done this will define
+#
+# MKL_FOUND - system has Intel MKL
+# MKL_INCLUDE_DIRS - the MKL include directories
+# MKL_LIBRARIES - link these to use MKL
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# MKL_PATH - root directory of the MKL installation
+# MKL_ROOT - root directory of the MKL installation
+
+option( MKL_PARALLEL "if mkl shoudl be parallel" OFF )
+
+if( MKL_PARALLEL )
+
+ set( __mkl_lib_par MKL_LIB_INTEL_THREAD )
+ set( __mkl_lib_name mkl_intel_thread )
+
+ find_package(Threads)
+
+else()
+
+ set( __mkl_lib_par MKL_LIB_SEQUENTIAL )
+ set( __mkl_lib_name mkl_sequential )
+
+endif()
+
+# Search with priority for MKL_ROOT and MKL_PATH if set in CMake or env
+find_path(MKL_INCLUDE_DIR mkl.h
+ PATHS ${MKL_PATH} ${MKL_ROOT} ENV MKL_PATH MKL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+find_path(MKL_INCLUDE_DIR mkl.h
+ PATH_SUFFIXES include)
+
+if( MKL_INCLUDE_DIR ) # use include dir to find libs
+
+ set( MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} )
+
+ if( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" )
+ get_filename_component( MKL_LIB_PATH ${MKL_INCLUDE_DIR}/../lib/intel64 ABSOLUTE )
+ set( __libsfx _lp64 )
+ else()
+ get_filename_component( MKL_LIB_PATH ${MKL_INCLUDE_DIR}/../lib/ia32 ABSOLUTE )
+ set( __libsfx "" )
+ endif()
+
+ message( STATUS "ICC_LIB_PATH ${ICC_LIB_PATH}" )
+
+ find_library( MKL_LIB_INTEL NAMES mkl_intel${__libsfx} PATHS ${MKL_LIB_PATH} )
+ find_library( ${__mkl_lib_par} NAMES ${__mkl_lib_name} PATHS ${MKL_LIB_PATH} )
+ find_library( MKL_LIB_CORE NAMES mkl_core PATHS ${MKL_LIB_PATH} )
+
+ if( MKL_PARALLEL )
+ find_library( MKL_LIB_IOMP5 NAMES iomp5 PATHS ${MKL_LIB_PATH} )
+ endif()
+
+ if( MKL_LIB_INTEL AND ${__mkl_lib_par} AND MKL_LIB_CORE )
+ set( MKL_LIBRARIES ${MKL_LIB_INTEL} ${${__mkl_lib_par}} ${MKL_LIB_CORE} ${MKL_LIB_IOMP5} ${CMAKE_THREAD_LIBS_INIT} )
+ endif()
+
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( MKL DEFAULT_MSG
+ MKL_LIBRARIES MKL_INCLUDE_DIRS )
+
+mark_as_advanced( MKL_INCLUDE_DIR MKL_LIB_LAPACK MKL_LIB_INTEL MKL_LIB_SEQUENTIAL MKL_LIB_CORE )
diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake
index 99ead8d..b214d27 100644
--- a/cmake/FindNetCDF.cmake
+++ b/cmake/FindNetCDF.cmake
@@ -23,7 +23,7 @@
# default is netcdf4
if( NetCDF_FIND_VERSION STREQUAL "3" )
- set( PREFER_NETCDF3 1 )
+ set( PREFER_NETCDF3 1 )
endif()
if( NOT PREFER_NETCDF3 )
@@ -40,87 +40,88 @@ set( NETCDF_FIND_COMPONENTS ${NetCDF_FIND_COMPONENTS} )
list( APPEND NETCDF_FIND_COMPONENTS C )
if( NETCDF_CXX )
- list( APPEND NETCDF_FIND_COMPONENTS CXX )
+ ecbuild_debug( "FindNetCDF: also looking for C++ libraries" )
+ list( APPEND NETCDF_FIND_COMPONENTS CXX )
endif()
if( NETCDF_Fortran OR NETCDF_FORTRAN OR NETCDF_F90 )
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
+ ecbuild_debug( "FindNetCDF: also looking for Fortran libraries" )
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
endif()
list(FIND NETCDF_FIND_COMPONENTS "FORTRAN" _index)
if(${_index} GREATER -1)
- list( APPEND NETCDF_FIND_COMPONENTS F90 )
+ list( APPEND NETCDF_FIND_COMPONENTS F90 )
endif()
list (FIND NETCDF_FIND_COMPONENTS "F90" _index)
if(${_index} GREATER -1)
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN )
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN )
endif()
list(FIND NETCDF_FIND_COMPONENTS "Fortran" _index)
if(${_index} GREATER -1)
- list( REMOVE_ITEM NETCDF_FIND_COMPONENTS Fortran )
- list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
+ list( REMOVE_ITEM NETCDF_FIND_COMPONENTS Fortran )
+ list( APPEND NETCDF_FIND_COMPONENTS FORTRAN F90 )
endif()
list( REMOVE_DUPLICATES NETCDF_FIND_COMPONENTS )
+ecbuild_debug( "FindNetCDF: looking for components ${NETCDF_FIND_COMPONENTS}" )
### NetCDF4
if( PREFER_NETCDF4 )
- ## hdf5
+ ecbuild_debug( "FindNetCDF: looking for NetCDF4" )
- ecbuild_add_extra_search_paths( hdf5 )
+ ## hdf5
- # Note: Only the HDF5 C-library is required for NetCDF
- # ( even for Fortan and CXX bindings)
- find_package( HDF5 COMPONENTS C QUIET )
+ # Note: Only the HDF5 C-library is required for NetCDF
+ # ( even for Fortan and CXX bindings)
+ find_package( HDF5 COMPONENTS C QUIET )
- ## netcdf4
+ ## netcdf4
- # CONFIGURE the NETCDF_FIND_COMPONENTS variable
+ # CONFIGURE the NETCDF_FIND_COMPONENTS variable
- # Find NetCDF4
+ # Find NetCDF4
- ecbuild_add_extra_search_paths( netcdf4 )
+ # message( "NETCDF CMAKE_PREFIX_PATH = [${CMAKE_PREFIX_PATH}]")
+ # debug_var( NETCDF_ROOT )
+ # debug_var( NETCDF_FIND_COMPONENTS )
+ # debug_var( NETCDF_FIND_QUIETLY )
+ # debug_var( NETCDF_FIND_REQUIRED )
+ find_package( NetCDF4 COMPONENTS ${NETCDF_FIND_COMPONENTS} )
+ # debug_var( NETCDF4_FOUND )
+ # debug_var( NETCDF_FOUND )
+ # debug_var( NETCDF_LIBRARIES )
+ # debug_var( NETCDF_INCLUDE_DIRS )
- # message( "NETCDF CMAKE_PREFIX_PATH = [${CMAKE_PREFIX_PATH}]")
- # debug_var( NETCDF_ROOT )
- # debug_var( NETCDF_FIND_COMPONENTS )
- # debug_var( NETCDF_FIND_QUIETLY )
- # debug_var( NETCDF_FIND_REQUIRED )
- find_package( NetCDF4 )
- # debug_var( NETCDF4_FOUND )
- # debug_var( NETCDF_FOUND )
- # debug_var( NETCDF_LIBRARIES )
- # debug_var( NETCDF_INCLUDE_DIRS )
+ list( APPEND NETCDF_Fortran_LIBRARIES ${NETCDF_FORTRAN_LIBRARIES} ${NETCDF_F90_LIBRARIES} )
+ if( NETCDF_Fortran_LIBRARIES )
+ list( REMOVE_DUPLICATES NETCDF_Fortran_LIBRARIES )
+ endif()
- list( APPEND NETCDF_Fortran_LIBRARIES ${NETCDF_FORTRAN_LIBRARIES} ${NETCDF_F90_LIBRARIES} )
- if( NETCDF_Fortran_LIBRARIES )
- list( REMOVE_DUPLICATES NETCDF_Fortran_LIBRARIES )
- endif()
+ # debug_var( NETCDF_Fortran_LIBRARIES )
+ # debug_var( NETCDF_C_LIBRARIES )
+ # debug_var( NETCDF_CXX_LIBRARIES )
- # debug_var( NETCDF_Fortran_LIBRARIES )
- # debug_var( NETCDF_C_LIBRARIES )
- # debug_var( NETCDF_CXX_LIBRARIES )
+ set_package_properties( NetCDF4 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF4 file format" )
- set_package_properties( NetCDF4 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF4 file format" )
+ if( NETCDF_FOUND AND HDF5_FOUND )
+ # list( APPEND NETCDF_DEFINITIONS ${HDF5_DEFINITIONS} )
+ list( APPEND NETCDF_LIBRARIES ${HDF5_HL_LIBRARIES} ${HDF5_LIBRARIES} )
+ list( APPEND NETCDF_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS} )
+ endif()
- if( NETCDF_FOUND AND HDF5_FOUND )
- # list( APPEND NETCDF_DEFINITIONS ${HDF5_DEFINITIONS} )
- list( APPEND NETCDF_LIBRARIES ${HDF5_HL_LIBRARIES} ${HDF5_LIBRARIES} )
- list( APPEND NETCDF_INCLUDE_DIRS ${HDF5_INCLUDE_DIRS} )
- endif()
-
- #debug_var( NETCDF_FOUND )
- #debug_var( NETCDF_LIBRARIES )
- #debug_var( NETCDF_INCLUDE_DIRS )
- #debug_var( HDF5_FOUND )
- #debug_var( HDF5_INCLUDE_DIRS )
- #debug_var( HDF5_HL_LIBRARIES )
- #debug_var( HDF5_LIBRARIES )
+ #debug_var( NETCDF_FOUND )
+ #debug_var( NETCDF_LIBRARIES )
+ #debug_var( NETCDF_INCLUDE_DIRS )
+ #debug_var( HDF5_FOUND )
+ #debug_var( HDF5_INCLUDE_DIRS )
+ #debug_var( HDF5_HL_LIBRARIES )
+ #debug_var( HDF5_LIBRARIES )
endif()
@@ -128,40 +129,36 @@ endif()
if( PREFER_NETCDF3 )
- # message( "LOOKING FOR NETCDF3" )
-
- # debug_var( NetCDF_FIND_COMPONENTS )
- # debug_var( NetCDF_FIND_QUIETLY )
- # debug_var( NetCDF_FIND_REQUIRED )
-
- list(FIND NetCDF_FIND_COMPONENTS "CXX" _index)
- if(${_index} GREATER -1)
- set( NETCDF_CXX 1 )
- endif()
+ ecbuild_debug( "FindNetCDF: looking for NetCDF3" )
- list(FIND NetCDF_FIND_COMPONENTS "Fortran" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
+ # debug_var( NetCDF_FIND_COMPONENTS )
+ # debug_var( NetCDF_FIND_QUIETLY )
+ # debug_var( NetCDF_FIND_REQUIRED )
- list(FIND NetCDF_FIND_COMPONENTS "FORTRAN" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
+ list(FIND NetCDF_FIND_COMPONENTS "CXX" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_CXX 1 )
+ endif()
- list(FIND NetCDF_FIND_COMPONENTS "F90" _index)
- if(${_index} GREATER -1)
- set( NETCDF_Fortran 1 )
- endif()
+ list(FIND NetCDF_FIND_COMPONENTS "Fortran" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
- ecbuild_add_extra_search_paths( netcdf3 )
+ list(FIND NetCDF_FIND_COMPONENTS "FORTRAN" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
- ecbuild_add_extra_search_paths( netcdf ) # fallback to netcdf search paths
+ list(FIND NetCDF_FIND_COMPONENTS "F90" _index)
+ if(${_index} GREATER -1)
+ set( NETCDF_Fortran 1 )
+ endif()
- message( "NETCDF CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}" )
+ #message( "NETCDF CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}" )
- find_package( NetCDF3 )
+ find_package( NetCDF3 COMPONENTS ${NETCDF_FIND_COMPONENTS} )
- set_package_properties( NetCDF3 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF3 file format" )
+ set_package_properties( NetCDF3 PROPERTIES TYPE RECOMMENDED PURPOSE "support for NetCDF3 file format" )
endif()
diff --git a/cmake/FindNetCDF3.cmake b/cmake/FindNetCDF3.cmake
index 079e55e..20a5396 100644
--- a/cmake/FindNetCDF3.cmake
+++ b/cmake/FindNetCDF3.cmake
@@ -9,10 +9,12 @@
# Try to find NetCDF
#
# Input:
-# * NETCDF_PATH - user defined path where to search for the library first
-# * NETCDF_DIR - user defined path where to search for the library first
-# * NETCDF_CXX - if to search also for netcdf_c++ wrapper library
-# * NETCDF_Fortran - if to search also for netcdff wrapper library
+# * NETCDF_PATH - user defined path where to search for the library first
+# (CMake or environment variable)
+# * NETCDF_DIR - user defined path where to search for the library first
+# (CMake or environment variable)
+# * NETCDF_CXX - search also for netcdf_c++ wrapper library
+# * NETCDF_Fortran - search also for netcdff wrapper library
#
# Output:
# NETCDF_FOUND - System has NetCDF
@@ -21,14 +23,6 @@
### TODO: generalize this into a macro for all ecbuild
-if( DEFINED $ENV{NETCDF_PATH} )
- list( APPEND CMAKE_PREFIX_PATH $ENV{NETCDF_PATH} )
-endif()
-
-if( DEFINED $ENV{NETCDF_DIR} )
- list( APPEND CMAKE_PREFIX_PATH $ENV{NETCDF_DIR} )
-endif()
-
if( DEFINED NETCDF_PATH )
list( APPEND _netcdf_incs ${NETCDF_PATH} ${NETCDF_PATH}/include )
list( APPEND _netcdf_libs ${NETCDF_PATH} ${NETCDF_PATH}/lib )
@@ -39,33 +33,20 @@ if( DEFINED NETCDF_DIR )
list( APPEND _netcdf_libs ${NETCDF_DIR} ${NETCDF_DIR}/lib )
endif()
-foreach( _h /usr/local/apps/netcdf )
-
- if( EXISTS ${_h} )
-
- list( APPEND _netcdf_incs ${_h}/include ${_h}/current/include ${_h}/new/include ${_h}/stable/include )
- list( APPEND _netcdf_libs ${_h}/lib ${_h}/current/lib ${_h}/new/lib ${_h}/stable/lib )
-
- file(GLOB _hd ${_h}/*)
- foreach( d ${_hd} )
- if( IS_DIRECTORY ${d} )
- list( APPEND _netcdf_incs ${d}/include ${d}/LP64/include )
- list( APPEND _netcdf_libs ${d}/lib ${d}/LP64/lib )
- endif()
- endforeach()
- endif()
-
-endforeach()
+# Honour environment variables NETCDF_DIR, NETCDF_PATH
+list( APPEND _netcdf_incs ENV NETCDF_DIR ENV NETCDF_PATH )
+list( APPEND _netcdf_libs ENV NETCDF_DIR ENV NETCDF_PATH )
###
-set( _ncdf_sfx netcdf LP64 )
+set( _inc_sfx netcdf include )
+set( _lib_sfx netcdf lib64 lib )
-find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
-find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
+find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH )
+find_path( NETCDF_INCLUDE_DIR netcdf.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
-find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
-find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
+find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+find_library( NETCDF_LIBRARY netcdf PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
set( NETCDF_LIBRARIES ${NETCDF_LIBRARY} )
set( NETCDF_INCLUDE_DIRS ${NETCDF_INCLUDE_DIR} )
@@ -76,13 +57,13 @@ list( APPEND NETCDF_REQUIRED_VARS NETCDF_LIBRARY NETCDF_INCLUDE_DIR )
if( NETCDF_CXX )
- find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH)
- find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
+ find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH)
+ find_path( NETCDF_CXX_INCLUDE_DIR netcdfcpp.h PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
set( _ncdf_cxx netcdf_c++ netcdf_c++ netcdf_c++4 )
- find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
- find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
+ find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+ find_library( NETCDF_CXX_LIBRARY NAMES ${_ncdf_cxx} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_CXX_INCLUDE_DIR} )
list( APPEND NETCDF_LIBRARIES ${NETCDF_CXX_LIBRARY} )
@@ -95,13 +76,13 @@ endif()
if( NETCDF_Fortran )
- find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH)
- find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_ncdf_sfx} )
+ find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} NO_DEFAULT_PATH)
+ find_path( NETCDF_Fortran_INCLUDE_DIR netcdf.mod PATHS ${_netcdf_incs} PATH_SUFFIXES ${_inc_sfx} )
set( _ncdf_fortran netcdff )
- find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} NO_DEFAULT_PATH )
- find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_ncdf_sfx} )
+ find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} NO_DEFAULT_PATH )
+ find_library( NETCDF_Fortran_LIBRARY NAMES ${_ncdf_fortran} PATHS ${_netcdf_libs} PATH_SUFFIXES ${_lib_sfx} )
list( APPEND NETCDF_INCLUDE_DIRS ${NETCDF_Fortran_INCLUDE_DIR} )
list( APPEND NETCDF_LIBRARIES ${NETCDF_Fortran_LIBRARY} )
diff --git a/cmake/FindOpenCL.cmake b/cmake/FindOpenCL.cmake
new file mode 100644
index 0000000..e4e9556
--- /dev/null
+++ b/cmake/FindOpenCL.cmake
@@ -0,0 +1,67 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find OpenCL
+# Once done this will define
+#
+# OPENCL_FOUND - system has OpenCL
+# OPENCL_INCLUDE_DIRS - the OpenCL include directory
+# OPENCL_LIBRARIES - link these to use OpenCL
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# OPENCL_ROOT - root folder of the OpenCL installation
+# CUDA_TOOLKIT_ROOT_DIR - root folder of the CUDA installation (ships OpenCL)
+# CUDA_ROOT - root folder of the CUDA installation (ships OpenCL)
+
+if(UNIX)
+
+ if(APPLE)
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_path(OPENCL_INCLUDE_DIRS OpenCL/cl.h
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+ find_path(OPENCL_INCLUDE_DIRS OpenCL/cl.h
+ PATH_SUFFIXES include )
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES lib NO_DEFAULT_PATH)
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATH_SUFFIXES lib )
+
+ else()
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_path(OPENCL_INCLUDE_DIRS NAMES CL/cl.h CL/opencl.h
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+ find_path(OPENCL_INCLUDE_DIRS NAMES CL/cl.h CL/opencl.h
+ PATHS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_ROOT} /usr/local/cuda
+ PATH_SUFFIXES include )
+
+ # Search with priority for OPENCL_ROOT if given as CMake or env var
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${OPENCL_ROOT} ENV OPENCL_ROOT
+ PATH_SUFFIXES lib64 lib NO_DEFAULT_PATH)
+ find_library(OPENCL_LIBRARIES OpenCL
+ PATHS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_ROOT} /usr/local/cuda
+ PATH_SUFFIXES lib64 lib )
+
+ endif()
+
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args( OPENCL DEFAULT_MSG
+ OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS )
+
+mark_as_advanced( OPENCL_INCLUDE_DIRS OPENCL_LIBRARIES )
diff --git a/cmake/FindOpenJPEG.cmake b/cmake/FindOpenJPEG.cmake
index 3e36954..d692f35 100644
--- a/cmake/FindOpenJPEG.cmake
+++ b/cmake/FindOpenJPEG.cmake
@@ -16,12 +16,11 @@
# OPENJPEG_LIBRARY, where to find the OpenJPEG library.
# OPENJPEG_INCLUDE_DIR, where to find the openjpeg.h header
-ecbuild_add_extra_search_paths( openjpg )
-
IF( NOT DEFINED OPENJPEG_PATH AND NOT "$ENV{OPENJPEG_PATH}" STREQUAL "" )
SET( OPENJPEG_PATH "$ENV{OPENJPEG_PATH}" )
ENDIF()
+# TODO: This only works for OpenJPEG v1.x.y and not for v2 which has a different API, library name etc
if( DEFINED OPENJPEG_PATH )
find_path(OPENJPEG_INCLUDE_DIR openjpeg.h PATHS ${OPENJPEG_PATH}/include PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
find_library(OPENJPEG_LIBRARY openjpeg PATHS ${OPENJPEG_PATH}/lib PATH_SUFFIXES openjpeg NO_DEFAULT_PATH)
diff --git a/cmake/FindPango.cmake b/cmake/FindPango.cmake
index 81b55c0..0105d7f 100644
--- a/cmake/FindPango.cmake
+++ b/cmake/FindPango.cmake
@@ -13,8 +13,6 @@
# PANGO_LIBRARIES
# PANGO_INCLUDE_DIRS
-ecbuild_add_extra_search_paths( pango )
-
find_package(PkgConfig)
pkg_check_modules(PC_LIBPANGO QUIET pango)
diff --git a/cmake/FindPangoCairo.cmake b/cmake/FindPangoCairo.cmake
index 4fb1fd2..611e269 100644
--- a/cmake/FindPangoCairo.cmake
+++ b/cmake/FindPangoCairo.cmake
@@ -1,8 +1,8 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
@@ -21,15 +21,18 @@ pkg_check_modules(PC_LIBPANGOCAIRO QUIET pangocairo)
#debug_var( PC_LIBPANGOCAIRO_FOUND )
#debug_var( PC_LIBPANGOCAIRO_VERSION )
#debug_var( PC_LIBPANGOCAIRO_LIBRARIES )
+#debug_var( PC_LIBPANGOCAIRO_LDFLAGS )
+#debug_var( PC_LIBPANGOCAIRO_LDFLAGS_OTHER )
#debug_var( PC_LIBPANGOCAIRO_INCLUDE_DIRS )
-
if(PC_LIBPANGOCAIRO_FOUND)
+
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args( pangocairo DEFAULT_MSG PC_LIBPANGOCAIRO_LIBRARIES PC_LIBPANGOCAIRO_INCLUDE_DIRS )
set( PANGOCAIRO_VERSION ${PC_LIBPANGOCAIRO_VERSION} )
- set( PANGOCAIRO_LIBRARIES ${PC_LIBPANGOCAIRO_LIBRARIES} )
+ set( PANGOCAIRO_LIBRARIES "${PC_LIBPANGOCAIRO_LDFLAGS} ${PC_LIBPANGOCAIRO_LDFLAGS_OTHER}" )
set( PANGOCAIRO_INCLUDE_DIRS ${PC_LIBPANGOCAIRO_INCLUDE_DIRS} )
+
else()
# this is to get magics compiling on mac with macbrew
diff --git a/cmake/FindProj4.cmake b/cmake/FindProj4.cmake
index 6181ed0..6774b6e 100644
--- a/cmake/FindProj4.cmake
+++ b/cmake/FindProj4.cmake
@@ -7,12 +7,14 @@
#
# Define PROJ4_MIN_VERSION for which version desired.
-if( NOT PROJ4_PATH AND NOT "$ENV{PROJ4_PATH}" STREQUAL "" )
- set( PROJ4_PATH "$ENV{PROJ4_PATH}" )
+if( NOT PROJ4_PATH )
+ if ( NOT "$ENV{PROJ4_PATH}" STREQUAL "" )
+ set( PROJ4_PATH "$ENV{PROJ4_PATH}" )
+ elseif ( NOT "$ENV{PROJ4_DIR}" STREQUAL "" )
+ set( PROJ4_PATH "$ENV{PROJ4_DIR}" )
+ endif()
endif()
-ecbuild_add_extra_search_paths( proj4 )
-
if( NOT PROJ4_PATH )
include(FindPkgConfig)
diff --git a/cmake/FindSZip.cmake b/cmake/FindSZip.cmake
index 533df50..d7d6026 100644
--- a/cmake/FindSZip.cmake
+++ b/cmake/FindSZip.cmake
@@ -12,8 +12,6 @@
# SZIP_INCLUDE_DIRS - The SZip include directories
# SZIP_LIBRARIES - The libraries needed to use SZip
-ecbuild_add_extra_search_paths( szip )
-
if( DEFINED SZIP_PATH )
find_path( SZIP_INCLUDE_DIR szlib.h PATHS ${SZIP_PATH}/include PATH_SUFFIXES szip NO_DEFAULT_PATH )
find_library( SZIP_LIBRARY NAMES szip sz PATHS ${SZIP_PATH}/lib PATH_SUFFIXES szip NO_DEFAULT_PATH )
diff --git a/cmake/FindScin.cmake b/cmake/FindScin.cmake
deleted file mode 100644
index 3ddf732..0000000
--- a/cmake/FindScin.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# (C) Copyright 1996-2014 ECMWF.
-#
-# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-# - Try to find ECREGRID
-# Once done this will define
-# ECREGRID_FOUND - System has ECREGRID
-# ECREGRID_INCLUDE_DIRS - The ECREGRID include directories
-# ECREGRID_LIBRARIES - The libraries needed to use ECREGRID
-# ECREGRID_DEFINITIONS - Compiler switches required for using ECREGRID
-
-option( WITH_ECREGRID "try to find scin installation" ON )
-
-# skip if ECREGRID is already found or if has is built inside
-
-if( NOT ECREGRID_FOUND AND WITH_ECREGRID )
-
- if( NOT DEFINED ECREGRID_PATH AND NOT "$ENV{ECREGRID_PATH}" STREQUAL "" )
- list( APPEND ECREGRID_PATH "$ENV{ECREGRID_PATH}" )
- endif()
-
- if( DEFINED ECREGRID_PATH )
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/include PATH_SUFFIXES scin_api NO_DEFAULT_PATH )
- find_library(ECREGRID_LIBRARY NAMES scin PATHS ${ECREGRID_PATH} ${ECREGRID_PATH}/lib PATH_SUFFIXES scin NO_DEFAULT_PATH )
- endif()
-
- find_path(ECREGRID_INCLUDE_DIR NAMES scin_api.h PATH_SUFFIXES scin_api )
- find_library( ECREGRID_LIBRARY NAMES scin PATH_SUFFIXES scin )
-
- include(FindPackageHandleStandardArgs)
-
- # handle the QUIETLY and REQUIRED arguments and set ECREGRID_FOUND to TRUE
- # if all listed variables are TRUE
- find_package_handle_standard_args(Scin DEFAULT_MSG
- ECREGRID_LIBRARY ECREGRID_INCLUDE_DIR)
-
- if( ECREGRID_FOUND )
- set( ECREGRID_LIBRARIES ${ECREGRID_LIBRARY} )
- set( ECREGRID_INCLUDE_DIRS ${ECREGRID_INCLUDE_DIR} )
- endif()
-
- mark_as_advanced(ECREGRID_INCLUDE_DIR ECREGRID_LIBRARY )
-
-endif()
diff --git a/cmake/FindTrilinos.cmake b/cmake/FindTrilinos.cmake
index 717cca6..9cc6132 100644
--- a/cmake/FindTrilinos.cmake
+++ b/cmake/FindTrilinos.cmake
@@ -17,9 +17,6 @@
# Try to find Trilinos using Trilinos recommendations
-
-ecbuild_add_extra_search_paths( trilinos )
-
if( DEFINED $ENV{TRILINOS_PATH} )
find_package(Trilinos PATHS $ENV{TRILINOS_PATH}/lib/cmake/Trilinos $ENV{TRILINOS_PATH}/include )
endif()
diff --git a/cmake/FindViennaCL.cmake b/cmake/FindViennaCL.cmake
new file mode 100644
index 0000000..a1b1eb9
--- /dev/null
+++ b/cmake/FindViennaCL.cmake
@@ -0,0 +1,38 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# - Try to find ViennaCL
+# Once done this will define
+#
+# VIENNACL_FOUND - system has ViennaCL
+# VIENNACL_INCLUDE_DIRS - the ViennaCL include directories
+#
+# The following paths will be searched with priority if set in CMake or env
+#
+# VIENNACL_PATH - prefix path of the ViennaCL installation
+#
+# ViennaCL is header only, so there are no libraries to be found
+
+# Search with priority for VIENNACL_PATH if given as CMake or env var
+find_path(VIENNACL_INCLUDE_DIR viennacl/version.hpp
+ PATHS ${VIENNACL_PATH} ENV VIENNACL_PATH
+ PATH_SUFFIXES include NO_DEFAULT_PATH)
+
+find_path(VIENNACL_INCLUDE_DIR viennacl/version.hpp
+ PATH_SUFFIXES include )
+
+set( VIENNACL_INCLUDE_DIRS ${VIENNACL_INCLUDE_DIR} )
+
+include(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set VIENNACL_FOUND to TRUE
+# if all listed variables are valid
+find_package_handle_standard_args(VIENNACL DEFAULT_MSG
+ VIENNACL_INCLUDE_DIR)
+
+mark_as_advanced(VIENNACL_INCLUDE_DIRS)
diff --git a/cmake/Findgrib_api.cmake b/cmake/Findgrib_api.cmake
index 55a7b19..32a01e9 100644
--- a/cmake/Findgrib_api.cmake
+++ b/cmake/Findgrib_api.cmake
@@ -19,8 +19,6 @@ option( GRIB_API_JPG "use jpg with grib_api" ON )
if( NOT grib_api_FOUND AND NOT NO_GRIB_API_BINARIES )
- ecbuild_add_extra_search_paths( grib_api )
-
if( GRIB_API_JPG ) # jpeg support
find_package( JPEG QUIET ) # grib_api might be a static .a library in which
diff --git a/cmake/Findodb_api.cmake b/cmake/Findodb_api.cmake
index c573d9b..5cd2a10 100644
--- a/cmake/Findodb_api.cmake
+++ b/cmake/Findodb_api.cmake
@@ -15,8 +15,6 @@
if( NOT odb_api_FOUND )
- ecbuild_add_extra_search_paths( odb_api )
-
# find external odb_api
if( NOT DEFINED ODB_API_PATH AND NOT "$ENV{ODB_API_PATH}" STREQUAL "" )
diff --git a/cmake/Findspot.cmake b/cmake/Findspot.cmake
index 6396ef0..1edb2cd 100644
--- a/cmake/Findspot.cmake
+++ b/cmake/Findspot.cmake
@@ -15,8 +15,6 @@
if( NOT spot_FOUND )
- ecbuild_add_extra_search_paths( spot )
-
# find external odb_api
if( NOT DEFINED SPOT_PATH AND NOT "$ENV{SPOT_PATH}" STREQUAL "" )
diff --git a/cmake/VERSION.cmake b/cmake/VERSION.cmake
index 40762d8..a07bd4a 100644
--- a/cmake/VERSION.cmake
+++ b/cmake/VERSION.cmake
@@ -1,7 +1,7 @@
set( ECBUILD_MAJOR_VERSION "1" )
-set( ECBUILD_MINOR_VERSION "7" )
+set( ECBUILD_MINOR_VERSION "9" )
set( ECBUILD_PATCH_VERSION "0" )
-set( ECBUILD_VERSION_STR "1.7.0" )
+set( ECBUILD_VERSION_STR "1.9.0" )
set( ECBUILD_MACRO_VERSION "${ECBUILD_MAJOR_VERSION}.${ECBUILD_MINOR_VERSION}" )
diff --git a/cmake/contrib/FindEigen3.cmake b/cmake/contrib/FindEigen3.cmake
index 72d4a9d..9315294 100644
--- a/cmake/contrib/FindEigen3.cmake
+++ b/cmake/contrib/FindEigen3.cmake
@@ -15,8 +15,6 @@
# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1 at gmail.com>
# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
-ecbuild_add_extra_search_paths( eigen )
-
if(NOT Eigen3_FIND_VERSION)
if(NOT Eigen3_FIND_VERSION_MAJOR)
set(Eigen3_FIND_VERSION_MAJOR 2)
@@ -76,7 +74,13 @@ else(EIGEN3_INCLUDE_DIR)
${EIGEN_PATH}/include
${EIGEN_DIR}/include
${EIGEN_ROOT}/include
- PATH_SUFFIXES eigen3 eigen
+ ENV EIGEN3_PATH
+ ENV EIGEN3_DIR
+ ENV EIGEN3_ROOT
+ ENV EIGEN_PATH
+ ENV EIGEN_DIR
+ ENV EIGEN_ROOT
+ PATH_SUFFIXES eigen3 eigen include/eigen3 include/eigen
)
if(EIGEN3_INCLUDE_DIR)
diff --git a/cmake/contrib/FindFFTW.cmake b/cmake/contrib/FindFFTW.cmake
index 1ddaf4c..d76767b 100644
--- a/cmake/contrib/FindFFTW.cmake
+++ b/cmake/contrib/FindFFTW.cmake
@@ -12,27 +12,55 @@
# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found
# FFTW_ROOT ... if set, the libraries are exclusively searched
# under this path
+# FFTW_DIR ... equivalent to FFTW_ROOT
+# FFTW_PATH ... equivalent to FFTW_ROOT
# FFTW_LIBRARY ... fftw library to use
# FFTW_INCLUDE_DIR ... fftw include directory
#
-#=======================#
-#
-# From Eigen3
-#
-#========================
+#============================================#
+# #
+# From Eigen3, modified by W Deconinck #
+# #
+#============================================#
-#If environment variable FFTWDIR is specified, it has same effect as FFTW_ROOT
-if( NOT FFTW_ROOT AND ENV{FFTWDIR} )
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_ROOT} )
+ set( FFTW_ROOT ${FFTW_ROOT} )
+endif()
+if( NOT FFTW_ROOT AND $FFTW_DIR )
+ set( FFTW_ROOT ${FFTW_DIR} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_DIR} )
+ set( FFTW_ROOT $ENV{FFTW_DIR} )
+endif()
+if( (NOT FFTW_ROOT) AND FFTWDIR )
+ set( FFTW_ROOT ${FFTWDIR} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTWDIR} )
set( FFTW_ROOT $ENV{FFTWDIR} )
endif()
+if( (NOT FFTW_ROOT) AND FFTW_PATH )
+ set( FFTW_ROOT ${FFTW_PATH} )
+endif()
+if( (NOT FFTW_ROOT) AND EXISTS $ENV{FFTW_PATH})
+ set( FFTW_ROOT $ENV{FFTW_PATH} )
+endif()
+
+if( FFTW_ROOT ) # On cc[a|b|t] FFTW_DIR is set to the lib directory :(
+ get_filename_component(_dirname ${FFTW_ROOT} NAME)
+ if( _dirname MATCHES "lib" )
+ set( FFTW_ROOT "${FFTW_ROOT}/.." )
+ endif()
+endif()
-# Check if we can use PkgConfig
-find_package(PkgConfig)
+if( NOT FFTW_ROOT )
+ # Check if we can use PkgConfig
+ find_package(PkgConfig)
-#Determine from PKG
-if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
- pkg_check_modules( PKG_FFTW QUIET "fftw3" )
+ #Determine from PKG
+ if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
+ pkg_check_modules( PKG_FFTW QUIET "fftw3" )
+ endif()
endif()
#Check whether to search static or dynamic libs
diff --git a/cmake/contrib/FindNetCDF4.cmake b/cmake/contrib/FindNetCDF4.cmake
index 33e7b36..89b0337 100644
--- a/cmake/contrib/FindNetCDF4.cmake
+++ b/cmake/contrib/FindNetCDF4.cmake
@@ -22,8 +22,9 @@
# NETCDF_USE_STATIC_LIBRARIES variable is set before the call to find_package.
#
# To provide the module with a hint about where to find your NETCDF installation,
-# you can set the environment variable NETCDF_ROOT. The Find module will then
-# look in this path when searching for NETCDF executables, paths, and libraries.
+# set the CMake or environment variable NETCDF_ROOT, NETCDF_DIR, NETCDF_PATH or
+# NETCDF4_DIR. The Find module will then look in this path when searching for
+# NETCDF executables, paths, and libraries.
#
# In addition to finding the includes and libraries required to compile an NETCDF
# client application, this module also makes an effort to find tools that come
@@ -90,11 +91,12 @@ endmacro()
# try to find the NETCDF wrapper compilers
find_program( NETCDF_CONFIG_EXECUTABLE
NAMES nc-config
- HINTS ENV NETCDF_ROOT
- PATHS
+ HINTS ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
PATH_SUFFIXES bin Bin
DOC "NETCDF CONFIG PROGRAM. Used only to detect NETCDF compile flags." )
mark_as_advanced( NETCDF_CONFIG_EXECUTABLE )
+ecbuild_debug("FindNetCDF4: nc-config executable = ${NETCDF_CONFIG_EXECUTABLE}")
set(output "no")
_NETCDF_CONFIG (--has-hdf5 output return)
@@ -154,16 +156,15 @@ else()
set( NETCDF_REQUIRED netcdf.h netcdfcpp.h netcdf.mod typesizes.mod netcdf netcdff netcdf_c++)
foreach( LANGUAGE ${NETCDF_LANGUAGE_BINDINGS} )
- # debug_var(LANGUAGE)
+ ecbuild_debug("FindNetCDF4: looking for ${LANGUAGE} language bindings")
set( NETCDF_${LANGUAGE}_FOUND 1 ) # disable this in following if necessary
# find the NETCDF includes
foreach( INC ${NETCDF_${LANGUAGE}_INCLUDE_NAMES} )
find_path( NETCDF_${INC}_INCLUDE_DIR ${INC}
- HINTS
- ${NETCDF_${LANGUAGE}_INCLUDE_FLAGS}
- ENV NETCDF_ROOT
- PATHS
+ HINTS ${NETCDF_${LANGUAGE}_INCLUDE_FLAGS}
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
PATH_SUFFIXES
include
Include
@@ -203,14 +204,14 @@ else()
find_library( NETCDF_${LIB}_LIBRARY_DEBUG
NAMES ${THIS_LIBRARY_SEARCH_DEBUG}
HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
- ENV NETCDF_ROOT
- PATHS
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
PATH_SUFFIXES lib64 Lib64 lib Lib)
find_library( NETCDF_${LIB}_LIBRARY_RELEASE
NAMES ${THIS_LIBRARY_SEARCH_RELEASE}
HINTS ${NETCDF_${LANGUAGE}_LIBRARY_DIRS}
- ENV NETCDF_ROOT
- PATHS
+ ${NETCDF_ROOT} ${NETCDF_DIR} ${NETCDF_PATH} ${NETCDF4_DIR}
+ ENV NETCDF_ROOT ENV NETCDF_DIR ENV NETCDF_PATH ENV NETCDF4_DIR
PATH_SUFFIXES lib64 Lib64 lib Lib )
select_library_configurations( NETCDF_${LIB} )
# even though we adjusted the individual library names in
@@ -231,7 +232,6 @@ else()
endif()
if (NETCDF_${LIB}_LIBRARY_RELEASE OR NETCDF_${LIB}_LIBRARY_DEBUG )
else()
- # message( STATUS "\"${LIB}\" is not found." )
list( FIND NETCDF_REQUIRED ${LIB} location )
if( ${location} EQUAL -1 )
else()
@@ -250,8 +250,8 @@ else()
# Append the libraries for this language binding to the list of all
# required libraries.
- # debug_var( NETCDF_${LANGUAGE}_FOUND )
if( NETCDF_${LANGUAGE}_FOUND )
+ ecbuild_debug( "FindNetCDF4: ${LANGUAGE} language bindings found" )
if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
list( APPEND NETCDF_${LANGUAGE}_LIBRARIES
debug ${NETCDF_${LANGUAGE}_LIBRARIES_DEBUG}
diff --git a/cmake/ecbuild_add_c_flags.cmake b/cmake/ecbuild_add_c_flags.cmake
new file mode 100644
index 0000000..012c2d6
--- /dev/null
+++ b/cmake/ecbuild_add_c_flags.cmake
@@ -0,0 +1,79 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_c_flags
+# ===================
+#
+# Add C compiler flags to CMAKE_C_FLAGS only if supported by the compiler. ::
+#
+# ecbuild_add_c_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_C_FLAGS_<build>`` instead of ``CMAKE_C_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+macro( ecbuild_add_c_flags m_c_flags )
+
+ set( _flags ${m_c_flags} )
+
+ if( _flags AND CMAKE_C_COMPILER_LOADED )
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( NOT DEFINED N_CFLAG )
+ set( N_CFLAG 0 )
+ endif()
+
+ math( EXPR N_CFLAG '${N_CFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_c_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_c_compiler_flag( ${_flags} C_FLAG_TEST_${N_CFLAG} )
+ set( _flag_ok ${C_FLAG_TEST_${N_CFLAG}} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_C_FLAGS_${_PAR_BUILD} "${CMAKE_C_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ else()
+ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flags}" )
+ ecbuild_debug( "C FLAG [${_flags}] added" )
+ endif()
+ else()
+ message( WARNING "Unrecognised C flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+ unset( _flags )
+ unset( _flag_ok )
+endmacro()
+
+macro( cmake_add_c_flags m_c_flags )
+ message( DEPRECATION " cmake_add_c_flags is deprecated, use ecbuild_add_c_flags instead." )
+ ecbuild_add_c_flags( ${m_c_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_cxx11_flags.cmake b/cmake/ecbuild_add_cxx11_flags.cmake
index 414f39f..7687bd9 100644
--- a/cmake/ecbuild_add_cxx11_flags.cmake
+++ b/cmake/ecbuild_add_cxx11_flags.cmake
@@ -6,17 +6,27 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to add cxx11 flags to compilation
-# uses macros from the project github.com/UCL/GreatCMakeCookOff
+##############################################################################
+#.rst:
+#
+# ecbuild_add_cxx11_flags
+# =======================
+#
+# Add cxx11 flags to CXX compilation flags. ::
+#
+# ecbuild_add_cxx11_flags()
+#
+# This macro uses macros from http://github.com/UCL/GreatCMakeCookOff.
+#
+##############################################################################
macro( ecbuild_add_cxx11_flags )
# if( CMAKE_COMPILER_IS_GNUCXX )
# if( CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7 )
- # cmake_add_cxx_flags("-std=c++0x")
+ # ecbuild_add_cxx_flags("-std=c++0x")
# else()
- # cmake_add_cxx_flags("-std=c++11")
+ # ecbuild_add_cxx_flags("-std=c++11")
# endif()
# endif()
diff --git a/cmake/ecbuild_add_cxx_flags.cmake b/cmake/ecbuild_add_cxx_flags.cmake
new file mode 100644
index 0000000..82644a5
--- /dev/null
+++ b/cmake/ecbuild_add_cxx_flags.cmake
@@ -0,0 +1,79 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_cxx_flags
+# =====================
+#
+# Add C++ compiler flags to CMAKE_CXX_FLAGS only if supported by compiler. ::
+#
+# ecbuild_add_cxx_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_CXX_FLAGS_<build>`` instead of ``CMAKE_CXX_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+macro( ecbuild_add_cxx_flags m_cxx_flags )
+
+ set( _flags ${m_cxx_flags} )
+ if( _flags AND CMAKE_CXX_COMPILER_LOADED )
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( NOT DEFINED N_CXXFLAG )
+ set( N_CXXFLAG 0 )
+ endif()
+
+ math( EXPR N_CXXFLAG '${N_CXXFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_cxx_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_cxx_compiler_flag( ${_flags} CXX_FLAG_TEST_${N_CXXFLAG} )
+ set( _flag_ok CXX_FLAG_TEST_${N_CXXFLAG} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_CXX_FLAGS_${_PAR_BUILD} "${CMAKE_CXX_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ else()
+ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flags}" )
+ ecbuild_debug( "C++ FLAG [${_flags}] added" )
+ endif()
+ else()
+ message( STATUS "Unrecognised CXX flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+ unset( _flags )
+ unset( _flag_ok )
+
+endmacro()
+
+macro( cmake_add_cxx_flags m_cxx_flags )
+ message( DEPRECATION " cmake_add_cxx_flags is deprecated, use ecbuild_add_cxx_flags instead." )
+ ecbuild_add_cxx_flags( ${m_cxx_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_executable.cmake b/cmake/ecbuild_add_executable.cmake
index 389505a..d1355c3 100644
--- a/cmake/ecbuild_add_executable.cmake
+++ b/cmake/ecbuild_add_executable.cmake
@@ -1,197 +1,296 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a test
+#.rst:
+#
+# ecbuild_add_executable
+# ======================
+#
+# Add an executable with a given list of source files. ::
+#
+# ecbuild_add_executable( TARGET <name>
+# SOURCES <source1> [<source2> ...]
+# [ TEMPLATES <template1> [<template2> ...] ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ NOINSTALL ]
+# [ VERSION <version> | AUTO_VERSION ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ]
+# [ OUTPUT_NAME <name> ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name
+#
+# SOURCES : required
+# list of source files
+#
+# TEMPLATES : optional
+# list of files specified as SOURCES which are not to be compiled separately
+# (these are commonly template implementation files included in a header)
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# CONDITION : optional
+# list of conditions, all of which must evaluate to true for this target to be built
+#
+# NOINSTALL : optional
+# do not install the executable
+#
+# VERSION : optional, AUTO_VERSION or LIBS_VERSION is used if not specified
+# version to use as executable version
+#
+# AUTO_VERSION : optional, ignored if VERSION is specified
+# automatically version the executable with the package version
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
+# OUTPUT_NAME : optional
+# sets the OUTPUT_NAME property on the target
+#
##############################################################################
macro( ecbuild_add_executable )
- set( options NOINSTALL AUTO_VERSION )
- set( single_value_args TARGET COMPONENT LINKER_LANGUAGE VERSION OUTPUT_NAME )
- set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
+ set( options NOINSTALL AUTO_VERSION )
+ set( single_value_args TARGET COMPONENT LINKER_LANGUAGE VERSION OUTPUT_NAME )
+ set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the TARGET.")
+ endif()
+
+ if( NOT _PAR_SOURCES )
+ message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the SOURCES.")
+ endif()
+
+ ### conditional build
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_executable(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ if( _${_PAR_TARGET}_condition )
+
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list(REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): add ${path} to include_directories")
+ include_directories( ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
endif()
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the TARGET.")
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
endif()
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_executable() doesn't specify the SOURCES.")
+ # remove templates from compilation sources
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): removing ${_PAR_TEMPLATES} from sources")
+ list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
+ add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
endif()
- ### conditional build
+ # add the executable target
+ add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
+ # set OUTPUT_NAME
+
+ if( DEFINED _PAR_OUTPUT_NAME )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set OUTPUT_NAME to ${_PAR_OUTPUT_NAME}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
endif()
- if( _${_PAR_TARGET}_condition )
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list(REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- include_directories( ${path} )
- # else()
- # message( WARNING "Path ${path} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add templates to project files and remove from compilation sources
- if( DEFINED _PAR_TEMPLATES )
- list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
- ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
- add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
- endif()
-
- # add the executable target
- add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
-
- # set OUTPUT_NAME
-
- if( DEFINED _PAR_OUTPUT_NAME )
- set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
- endif()
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
-# message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add local flags
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
- # define VERSION if requested
- if( DEFINED _PAR_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
- else()
- if( _PAR_AUTO_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
- endif()
- endif()
-
- # filter sources
-
- ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
-
-# debug_var( ${_PAR_TARGET}_h_srcs )
-# debug_var( ${_PAR_TARGET}_c_srcs )
-# debug_var( ${_PAR_TARGET}_cxx_srcs )
-# debug_var( ${_PAR_TARGET}_f_srcs )
-
- # installation
-
- if( NOT _PAR_NOINSTALL )
-
- # add installation paths and associate with defined component
-# if( DEFINED _PAR_COMPONENT )
-# set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
-# else()
-# set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
-# endif()
-
- install( TARGETS ${_PAR_TARGET}
- EXPORT ${CMAKE_PROJECT_NAME}-targets
- RUNTIME DESTINATION ${INSTALL_BIN_DIR}
- LIBRARY DESTINATION ${INSTALL_LIB_DIR}
- ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
-# COMPONENT ${COMPONENT_DIRECTIVE} )
-
- # set build location
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
-
- # export location of target to other projects -- must be exactly after setting the build location (see previous command)
-
- export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
-
- else()
- # NOINSTALL targets are always built the build_rpath, not the install_rpath
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
- endif()
-
- # add definitions to compilation
- if( DEFINED _PAR_DEFINITIONS )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
- endif()
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): ${lib} not found - not linking")
endif()
+ endforeach()
+ endif()
- # make sure target is removed before - some problems with AIX
- add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
-
- # for the links target
- if( NOT _PAR_NOINSTALL )
- ecbuild_link_exe( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
- endif()
+ # filter sources
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
- # append to the list of this project targets
- set( ${PROJECT_NAME}_ALL_EXES ${${PROJECT_NAME}_ALL_EXES} ${_PAR_TARGET} CACHE INTERNAL "" )
+ # add local flags
+ if( DEFINED _PAR_CFLAGS )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+ endif()
+ if( DEFINED _PAR_CXXFLAGS )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+ endif()
+ if( DEFINED _PAR_FFLAGS )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+ endif()
+ if( DEFINED _PAR_GENERATED )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): mark as generated ${_PAR_GENERATED}")
+ set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
+ endif()
+
+ # define VERSION if requested
+ if( DEFINED _PAR_VERSION )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set version to ${_PAR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
+ else()
+ if( _PAR_AUTO_VERSION )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): set version to ${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
+ endif()
+ endif()
+
+ # debug_var( ${_PAR_TARGET}_h_srcs )
+ # debug_var( ${_PAR_TARGET}_c_srcs )
+ # debug_var( ${_PAR_TARGET}_cxx_srcs )
+ # debug_var( ${_PAR_TARGET}_f_srcs )
+
+ # installation
+
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): installing to ${INSTALL_BIN_DIR}")
+
+ # add installation paths and associate with defined component
+ # if( DEFINED _PAR_COMPONENT )
+ # set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
+ # else()
+ # set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
+ # endif()
+
+ install( TARGETS ${_PAR_TARGET}
+ EXPORT ${CMAKE_PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+ LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+ ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
+ # COMPONENT ${COMPONENT_DIRECTIVE} )
+
+ # set build location
+
+ set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
+ # export location of target to other projects -- must be exactly after setting the build location (see previous command)
+
+ export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
+
+ else()
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): not installing")
+ # NOINSTALL targets are always built the build_rpath, not the install_rpath
+ set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
+ endif()
+
+ # add definitions to compilation
+ if( DEFINED _PAR_DEFINITIONS )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
+ endif()
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_executable(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ endif()
+
+ # make sure target is removed before - some problems with AIX
+ add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
+
+ # for the links target
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_link_exe( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
endif()
- # mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ # append to the list of this project targets
+ set( ${PROJECT_NAME}_ALL_EXES ${${PROJECT_NAME}_ALL_EXES} ${_PAR_TARGET} CACHE INTERNAL "" )
+
+ endif()
+
+ # mark source files as used
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
+ endif()
endmacro( ecbuild_add_executable )
diff --git a/cmake/ecbuild_add_extra_search_paths.cmake b/cmake/ecbuild_add_extra_search_paths.cmake
index 8e28091..c8a7a77 100644
--- a/cmake/ecbuild_add_extra_search_paths.cmake
+++ b/cmake/ecbuild_add_extra_search_paths.cmake
@@ -6,7 +6,7 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
+###############################################################################
#
# macro for adding search paths to CMAKE_PREFIX_PATH
# for example the ECMWF /usr/local/apps paths
@@ -15,20 +15,19 @@
function( ecbuild_add_extra_search_paths pkg )
-# debug_var( pkg )
+ message( DEPRECATION " ecbuild_add_extra_search_paths modifies CMAKE_PREFIX_PATH,"
+ " which can affect future package discovery if not undone by the caller."
+ " The current CMAKE_PREFIX_PATH is being backed up as _CMAKE_PREFIX_PATH"
+ " so it can later be restored." )
- ecbuild_list_extra_search_paths( ${pkg} CMAKE_PREFIX_PATH )
+ # Back up current CMAKE_PREFIX_PATH so the caller can reset it
+ set( _CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
- set( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
+ string( TOUPPER ${pkg} _PKG )
- # fixes BOOST_ROOT taking precedence on the search for location
- if( ${pkg} STREQUAL "boost" )
- if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
- set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
- endif()
- endif()
+ ecbuild_list_extra_search_paths( ${pkg} CMAKE_PREFIX_PATH )
-# debug_var( CMAKE_PREFIX_PATH )
+ set( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE )
+ # debug_var( CMAKE_PREFIX_PATH )
endfunction()
-
diff --git a/cmake/ecbuild_add_fortran_flags.cmake b/cmake/ecbuild_add_fortran_flags.cmake
new file mode 100644
index 0000000..827c39e
--- /dev/null
+++ b/cmake/ecbuild_add_fortran_flags.cmake
@@ -0,0 +1,85 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_add_fortran_flags
+# =========================
+#
+# Add Fortran compiler flags to CMAKE_Fortran_FLAGS only if supported by the
+# compiler. ::
+#
+# ecbuild_add_fortran_flags( <flag1> [ <flag2> ... ]
+# [ BUILD <build> ]
+# [ NAME <name> ] )
+#
+# Options
+# -------
+#
+# BUILD : optional
+# add flags to ``CMAKE_Fortran_FLAGS_<build>`` instead of
+# ``CMAKE_Fortran_FLAGS``
+#
+# NAME : optional
+# name of the check (if omitted, checks are enumerated)
+#
+##############################################################################
+
+include( CheckFortranCompilerFlag )
+macro( ecbuild_add_fortran_flags m_fortran_flags )
+
+ set( _flags ${m_fortran_flags} )
+
+ if( _flags AND CMAKE_Fortran_COMPILER_LOADED )
+
+ set( options )
+ set( single_value_args BUILD NAME )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( NOT DEFINED N_FortranFLAG )
+ set( N_FortranFLAG 0 )
+ endif()
+
+ math( EXPR N_FortranFLAG '${N_FortranFLAG}+1' )
+
+ if( NOT ECBUILD_TRUST_FLAGS )
+ if( DEFINED _PAR_NAME )
+ check_fortran_compiler_flag( ${_flags} ${_PAR_NAME} )
+ set( _flag_ok ${${_PAR_NAME}} )
+ else()
+ check_fortran_compiler_flag( ${_flags} Fortran_FLAG_TEST_${N_FortranFLAG} )
+ set( _flag_ok ${Fortran_FLAG_TEST_${N_FortranFLAG}} )
+ endif()
+ else()
+ set( _flag_ok 1 )
+ endif()
+
+ if( _flag_ok )
+ if( _PAR_BUILD )
+ set( CMAKE_Fortran_FLAGS_${_PAR_BUILD} "${CMAKE_Fortran_FLAGS_${_PAR_BUILD}} ${_flags}" )
+ else()
+ set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${_flags}" )
+ ecbuild_debug( "Fortran FLAG [${_flags}] added" )
+ endif()
+ else()
+ message( STATUS "Unrecognised Fortran flag [${_flags}] -- skipping" )
+ endif()
+ endif()
+
+ unset( _flags )
+ unset( _flag_ok )
+
+endmacro()
+
+macro( cmake_add_fortran_flags m_fortran_flags )
+ message( DEPRECATION " cmake_add_fortran_flags is deprecated, use ecbuild_add_fortran_flags instead." )
+ ecbuild_add_fortran_flags( ${m_fortran_flags} )
+endmacro()
diff --git a/cmake/ecbuild_add_library.cmake b/cmake/ecbuild_add_library.cmake
index a7e3dd2..49f9425 100644
--- a/cmake/ecbuild_add_library.cmake
+++ b/cmake/ecbuild_add_library.cmake
@@ -7,273 +7,436 @@
# does it submit to any jurisdiction.
##############################################################################
-# auxiliary macro for adding a library
+#.rst:
+#
+# ecbuild_add_library
+# ===================
+#
+# Add a library with a given list of source files. ::
+#
+# ecbuild_add_library( TARGET <name>
+# SOURCES <source1> [<source2> ...]
+# [ TYPE SHARED|STATIC|MODULE ]
+# [ TEMPLATES <template1> [<template2> ...] ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ PRIVATE_INCLUDES <path1> [<path2> ...] ]
+# [ PUBLIC_INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ NOINSTALL ]
+# [ HEADER_DESTINATION <path> ]
+# [ INSTALL_HEADERS LISTED|ALL ]
+# [ INSTALL_HEADERS_LIST <header1> [<header2> ...] ]
+# [ INSTALL_HEADERS_REGEX <pattern> ]
+# [ VERSION <version> | AUTO_VERSION ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ]
+# [ OUTPUT_NAME <name> ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name
+#
+# SOURCES : required
+# list of source files
+#
+# TYPE : optional
+# library type, one of:
+#
+# :SHARED: libraries are linked dynamically and loaded at runtime
+# :STATIC: archives of object files for use when linking other targets.
+# :MODULE: plugins that are not linked into other targets but may be loaded
+# dynamically at runtime using dlopen-like functionality
+#
+# TEMPLATES : optional
+# list of files specified as SOURCES which are not to be compiled separately
+# (these are commonly template implementation files included in a header)
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : (DEPRECATED) optional
+# list of paths to add to include directories, behaves as PUBLIC_INCLUDES if CMake >= 2.8.11
+# and reverts to include_directories() for CMake < 2.8.11
+#
+# PUBLIC_INCLUDES : optional
+# list of paths to add to include directories which will be publicly exported to other projects
+#
+# PRIVATE_INCLUDES : optional
+# list of paths to add to include directories which won't be exported to other projects,
+# equivalent to using a include_directories() before calling this macro
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# CONDITION : optional
+# list of conditions, all of which must evaluate to true for this target to be built
+#
+# NOINSTALL : optional
+# do not install the library
+#
+# HEADER_DESTINATION
+# directory to install headers (if not specified, INSTALL_INCLUDE_DIR is used)
+#
+# INSTALL_HEADERS : optional
+# specify which header files to install:
+#
+# :LISTED: install header files listed as SOURCES
+# :ALL: install all header files ending in .h, .hh, .hpp, .H
+#
+# INSTALL_HEADERS_LIST : optional
+# list of extra headers to install
+#
+# INSTALL_HEADERS_REGEX : optional
+# regular expression to match extra headers to install
+#
+# VERSION : optional, AUTO_VERSION or LIBS_VERSION is used if not specified
+# version to use as library version
+#
+# AUTO_VERSION : optional, ignored if VERSION is specified
+# automatically version the library with the package version
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
+# OUTPUT_NAME : optional
+# sets the OUTPUT_NAME property on the target
+#
##############################################################################
function( ecbuild_add_library_impl )
- set( options NOINSTALL AUTO_VERSION )
- set( single_value_args TARGET TYPE COMPONENT INSTALL_HEADERS LINKER_LANGUAGE HEADER_DESTINATION VERSION OUTPUT_NAME )
- set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES DEPENDS PERSISTENT DEFINITIONS CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_library(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT _PAR_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
- endif()
-
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the SOURCES.")
- endif()
-
- # get_filename_component( currdir ${CMAKE_CURRENT_SOURCE_DIR} NAME )
-
- # file(RELATIVE_PATH reldir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # debug_var( currdir )
- # debug_var( reldir )
-
- ### conditional build
-
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
- endif()
-
- if( _${_PAR_TARGET}_condition )
-
- # defines the type of library
- if( DEFINED _PAR_TYPE )
- # checks that is either SHARED or STATIC or MODULE
- if( NOT _PAR_TYPE MATCHES "STATIC" AND
- NOT _PAR_TYPE MATCHES "SHARED" AND
- NOT _PAR_TYPE MATCHES "MODULE" )
- message( FATAL_ERROR "library type must be one of [ STATIC | SHARED | MODULE ]" )
- endif()
- endif()
-
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add templates to project files and remove from compilation sources
- if( DEFINED _PAR_TEMPLATES )
- list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
- ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
- add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
- endif()
-
- add_library( ${_PAR_TARGET} ${_PAR_TYPE} ${_PAR_SOURCES} )
-
- # set OUTPUT_NAME
-
- if( DEFINED _PAR_OUTPUT_NAME )
- set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
- endif()
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
-# message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list( REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
- include_directories( ${path} )
- else()
- target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
- endif()
- # else()
- # message( WARNING "Path ${path} was skipped" )
- endif()
- endforeach()
- endif()
-
- # FIX: Cray compiler PIC option is not detected by CMake
-
- get_property( _target_pic TARGET ${_PAR_TARGET} PROPERTY POSITION_INDEPENDENT_CODE )
- if( _target_pic )
- if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_CFLAGS "-fPIC -h PIC ${_PAR_CFLAGS}" )
- endif()
- if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_CXXFLAGS "-fPIC -h PIC ${_PAR_CXXFLAGS}" )
- endif()
- if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
- set( _PAR_FFLAGS "-fPIC -h PIC ${_PAR_FFLAGS}" )
- endif()
- endif()
-
- # define VERSION if requested
- if( DEFINED _PAR_VERSION )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
- else()
- if( _PAR_AUTO_VERSION OR LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]")
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
- endif()
- if( LIBS_VERSION AND NOT LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]" )
- set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${LIBS_VERSION}" )
- endif()
- endif()
-
- # filter sources
-
- ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
-
-# debug_var( ${_PAR_TARGET}_h_srcs )
-# debug_var( ${_PAR_TARGET}_c_srcs )
-# debug_var( ${_PAR_TARGET}_cxx_srcs )
-# debug_var( ${_PAR_TARGET}_f_srcs )
-
- # add local flags
-
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
- endif()
-
- # installation
-
- if( NOT _PAR_NOINSTALL )
-
- # and associate with defined component
-# if( DEFINED _PAR_COMPONENT )
-# set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
-# else()
-# set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
-# endif()
-
- install( TARGETS ${_PAR_TARGET}
- EXPORT ${CMAKE_PROJECT_NAME}-targets
- RUNTIME DESTINATION ${INSTALL_BIN_DIR}
- LIBRARY DESTINATION ${INSTALL_LIB_DIR}
- ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
-# COMPONENT ${COMPONENT_DIRECTIVE} )
-
- # install headers
- if( _PAR_HEADER_DESTINATION )
- set( _h_destination "${_PAR_HEADER_DESTINATION}" )
- else()
- set( _h_destination "${INSTALL_INCLUDE_DIR}" )
- endif()
-
- if( _PAR_INSTALL_HEADERS )
- if( _PAR_INSTALL_HEADERS MATCHES "LISTED" )
- foreach( file ${${_PAR_TARGET}_h_srcs} )
- get_filename_component( _file_dir ${file} PATH )
- install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- if( DEFINED _PAR_TEMPLATES )
- foreach( file ${_PAR_TEMPLATES} )
- get_filename_component( _file_dir ${file} PATH )
- install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- endif()
- if( DEFINED _PAR_PERSISTENT )
- foreach( file ${_PAR_PERSISTENT} )
- get_filename_component( _file_dir ${file} PATH )
- get_filename_component( _file_we ${file} NAME_WE )
- set( pfile "${CMAKE_CURRENT_BINARY_DIR}/${_file_dir}/${_file_we}.b" )
- install( FILES ${pfile} DESTINATION "${_h_destination}/${_file_dir}" )
- endforeach()
- endif()
- endif()
- if( _PAR_INSTALL_HEADERS MATCHES "ALL" ) # "(\\.h|\\.b|\\.hxx|\\.hh|\\.hpp|\\.H)" ????
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.h" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hh" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hpp" )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.H" )
- endif()
- endif()
-
- if( DEFINED _PAR_INSTALL_HEADERS_LIST )
- install( FILES ${_PAR_INSTALL_HEADERS_LIST} DESTINATION ${_h_destination} )
- endif()
-
- if( DEFINED _PAR_INSTALL_HEADERS_REGEX )
- install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "${_PAR_INSTALL_HEADERS_REGEX}")
- endif()
-
- # set build location
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
- set_property( TARGET ${_PAR_TARGET} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
-
- # export location of target to other projects -- must be exactly after setting the build location (see previous 2 commands)
-
- export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
-
- endif()
-
- # add definitions to compilation
- if( DEFINED _PAR_DEFINITIONS )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
- endif()
-
- # make sure target is removed before - some problems with AIX
- add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
-
- # for the links target
- if( NOT _PAR_NOINSTALL )
- ecbuild_link_lib( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
- endif()
-
- # append to the list of this project targets
- set( ${PROJECT_NAME}_ALL_LIBS ${${PROJECT_NAME}_ALL_LIBS} ${_PAR_TARGET} CACHE INTERNAL "" )
-
- endif()
-
- # mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ set( options NOINSTALL AUTO_VERSION )
+ set( single_value_args TARGET TYPE COMPONENT INSTALL_HEADERS INSTALL_HEADERS_REGEX LINKER_LANGUAGE HEADER_DESTINATION VERSION OUTPUT_NAME )
+ set( multi_value_args SOURCES TEMPLATES LIBS INCLUDES PRIVATE_INCLUDES PUBLIC_INCLUDES DEPENDS PERSISTENT DEFINITIONS INSTALL_HEADERS_LIST CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_add_library(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT _PAR_TARGET )
+ message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
+ endif()
+
+ if( NOT _PAR_SOURCES )
+ message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the SOURCES.")
+ endif()
+
+ ### conditional build
+
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
+
+ if( _${_PAR_TARGET}_condition )
+
+ # defines the type of library
+ if( DEFINED _PAR_TYPE )
+ # checks that is either SHARED or STATIC or MODULE
+ if( NOT _PAR_TYPE MATCHES "STATIC" AND
+ NOT _PAR_TYPE MATCHES "SHARED" AND
+ NOT _PAR_TYPE MATCHES "MODULE" )
+ message( FATAL_ERROR "library type must be one of [ STATIC | SHARED | MODULE ]" )
+ endif()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): library type is ${_PAR_TYPE}")
+ endif()
+
+
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
+ endif()
+
+ # remove templates from compilation sources
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): removing ${_PAR_TEMPLATES} from sources")
+ list( REMOVE_ITEM _PAR_SOURCES ${_PAR_TEMPLATES} )
+ add_custom_target( ${_PAR_TARGET}_templates SOURCES ${_PAR_TEMPLATES} )
+ endif()
+
+ add_library( ${_PAR_TARGET} ${_PAR_TYPE} ${_PAR_SOURCES} )
+
+ # set OUTPUT_NAME
+
+ if( DEFINED _PAR_OUTPUT_NAME )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set OUTPUT_NAME to ${_PAR_OUTPUT_NAME}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES OUTPUT_NAME ${_PAR_OUTPUT_NAME} )
+ endif()
+
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
+
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${lib} not found - not linking")
+ endif()
+ endforeach()
+ endif()
+
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list( REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" OR ECBUILD_USE_INCLUDE_DIRECTORIES )
+ include_directories( ${path} )
+ else()
+ target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
+ endif()
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # add private include dirs if defined
+ if( DEFINED _PAR_PRIVATE_INCLUDES )
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
+ ecbuild_critical("ecbuild_add_library(${_PAR_TARGET}): cannot use PRIVATE_INCLUDES with CMake < 2.8.11" )
+ endif()
+ list( REMOVE_DUPLICATES _PAR_PRIVATE_INCLUDES )
+ foreach( path ${_PAR_PRIVATE_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ target_include_directories( ${_PAR_TARGET} PRIVATE ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # add public include dirs if defined
+ if( DEFINED _PAR_PUBLIC_INCLUDES )
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.11" )
+ ecbuild_critical("ecbuild_add_library(${_PAR_TARGET}): cannot use PUBLIC_INCLUDES with CMake < 2.8.11" )
+ endif()
+ list( REMOVE_DUPLICATES _PAR_PUBLIC_INCLUDES )
+ foreach( path ${_PAR_PUBLIC_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): add ${path} to include_directories")
+ target_include_directories( ${_PAR_TARGET} PUBLIC ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
+
+ # FIX: Cray compiler PIC option is not detected by CMake
+
+ get_property( _target_pic TARGET ${_PAR_TARGET} PROPERTY POSITION_INDEPENDENT_CODE )
+ if( _target_pic )
+ if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_CFLAGS "-fPIC -h PIC ${_PAR_CFLAGS}" )
+ endif()
+ if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_CXXFLAGS "-fPIC -h PIC ${_PAR_CXXFLAGS}" )
+ endif()
+ if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
+ set( _PAR_FFLAGS "-fPIC -h PIC ${_PAR_FFLAGS}" )
+ endif()
+ endif()
+
+ # define VERSION if requested
+ if( DEFINED _PAR_VERSION )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${_PAR_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${_PAR_VERSION}" )
+ else()
+ if( _PAR_AUTO_VERSION OR LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]")
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION} (auto)")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}" )
+ endif()
+ if( LIBS_VERSION AND NOT LIBS_VERSION MATCHES "[Aa][Uu][Tt][Oo]" )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): set version to ${LIBS_VERSION}")
+ set_target_properties( ${_PAR_TARGET} PROPERTIES VERSION "${LIBS_VERSION}" )
+ endif()
+ endif()
+
+ # filter sources
+
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
+
+ # debug_var( ${_PAR_TARGET}_h_srcs )
+ # debug_var( ${_PAR_TARGET}_c_srcs )
+ # debug_var( ${_PAR_TARGET}_cxx_srcs )
+ # debug_var( ${_PAR_TARGET}_f_srcs )
+
+ # add local flags
+
+ if( DEFINED _PAR_CFLAGS )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+ endif()
+ if( DEFINED _PAR_CXXFLAGS )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+ endif()
+ if( DEFINED _PAR_FFLAGS )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+ endif()
+ if( DEFINED _PAR_GENERATED )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): mark as generated ${_PAR_GENERATED}")
+ set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
+ endif()
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
+ endif()
+
+ # installation
+
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): installing to ${INSTALL_LIB_DIR}")
+
+ # and associate with defined component
+ # if( DEFINED _PAR_COMPONENT )
+ # set( COMPONENT_DIRECTIVE "${_PAR_COMPONENT}" )
+ # else()
+ # set( COMPONENT_DIRECTIVE "${PROJECT_NAME}" )
+ # endif()
+
+ install( TARGETS ${_PAR_TARGET}
+ EXPORT ${CMAKE_PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${INSTALL_BIN_DIR}
+ LIBRARY DESTINATION ${INSTALL_LIB_DIR}
+ ARCHIVE DESTINATION ${INSTALL_LIB_DIR} )
+ # COMPONENT ${COMPONENT_DIRECTIVE} )
+
+ # install headers
+ if( _PAR_HEADER_DESTINATION )
+ set( _h_destination "${_PAR_HEADER_DESTINATION}" )
+ else()
+ set( _h_destination "${INSTALL_INCLUDE_DIR}" )
+ endif()
+
+ if( _PAR_INSTALL_HEADERS )
+ if( _PAR_INSTALL_HEADERS MATCHES "LISTED" )
+ foreach( file ${${_PAR_TARGET}_h_srcs} )
+ get_filename_component( _file_dir ${file} PATH )
+ install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ if( DEFINED _PAR_TEMPLATES )
+ foreach( file ${_PAR_TEMPLATES} )
+ get_filename_component( _file_dir ${file} PATH )
+ install( FILES ${file} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ endif()
+ if( DEFINED _PAR_PERSISTENT )
+ foreach( file ${_PAR_PERSISTENT} )
+ get_filename_component( _file_dir ${file} PATH )
+ get_filename_component( _file_we ${file} NAME_WE )
+ set( pfile "${CMAKE_CURRENT_BINARY_DIR}/${_file_dir}/${_file_we}.b" )
+ install( FILES ${pfile} DESTINATION "${_h_destination}/${_file_dir}" )
+ endforeach()
+ endif()
+ endif()
+ if( _PAR_INSTALL_HEADERS MATCHES "ALL" ) # "(\\.h|\\.b|\\.hxx|\\.hh|\\.hpp|\\.H)" ????
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.h" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hh" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.hpp" )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "*.H" )
+ endif()
+ endif()
+
+ if( DEFINED _PAR_INSTALL_HEADERS_LIST )
+ install( FILES ${_PAR_INSTALL_HEADERS_LIST} DESTINATION ${_h_destination} )
+ endif()
+
+ if( DEFINED _PAR_INSTALL_HEADERS_REGEX )
+ install( DIRECTORY ./ DESTINATION ${_h_destination} FILES_MATCHING PATTERN "${_PAR_INSTALL_HEADERS_REGEX}")
+ endif()
+
+ # set build location
+
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
+
+ # export location of target to other projects -- must be exactly after setting the build location (see previous 2 commands)
+
+ export( TARGETS ${_PAR_TARGET} APPEND FILE "${TOP_PROJECT_TARGETS_FILE}" )
+
+ endif()
+
+ # add definitions to compilation
+ if( DEFINED _PAR_DEFINITIONS )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
+ ecbuild_debug("ecbuild_add_library(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
+ endif()
+
+ # make sure target is removed before - some problems with AIX
+ add_custom_command( TARGET ${_PAR_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E remove $<TARGET_FILE:${_PAR_TARGET}> )
+
+ # for the links target
+ if( NOT _PAR_NOINSTALL )
+ ecbuild_link_lib( ${_PAR_TARGET} $<TARGET_FILE_NAME:${_PAR_TARGET}> $<TARGET_FILE:${_PAR_TARGET}> )
+ endif()
+
+ # append to the list of this project targets
+ set( ${PROJECT_NAME}_ALL_LIBS ${${PROJECT_NAME}_ALL_LIBS} ${_PAR_TARGET} CACHE INTERNAL "" )
+
+ endif()
+
+ # mark source files as used
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ if( DEFINED _PAR_TEMPLATES )
+ ecbuild_declare_project_files( ${_PAR_TEMPLATES} )
+ endif()
endfunction( ecbuild_add_library_impl )
@@ -283,46 +446,46 @@ endfunction( ecbuild_add_library_impl )
macro( ecbuild_add_library )
- set( options )
- set( single_value_args TARGET TYPE )
- set( multi_value_args )
+ set( options )
+ set( single_value_args TARGET TYPE )
+ set( multi_value_args )
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if( DEFINED _p_TYPE ) # don't do anything if TYPE was specified
+ if( DEFINED _p_TYPE ) # don't do anything if TYPE was specified
- if( _p_TYPE MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
+ if( _p_TYPE MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
- ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
- ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} OUTPUT_NAME ${_p_TARGET} DEPENDS ${_p_TARGET} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} OUTPUT_NAME ${_p_TARGET} DEPENDS ${_p_TARGET} )
- else()
+ else()
- ecbuild_add_library_impl( ${ARGV} )
+ ecbuild_add_library_impl( ${ARGV} )
- endif()
+ endif()
- else()
+ else()
- if( NOT DEFINED _p_TARGET )
- message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
- else()
+ if( NOT DEFINED _p_TARGET )
+ message(FATAL_ERROR "The call to ecbuild_add_library() doesn't specify the TARGET.")
+ else()
- if( BUILD_SHARED_LIBS MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
+ if( BUILD_SHARED_LIBS MATCHES "[Bb][Oo][Tt][Hh]" ) # build both types
- ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
- ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} DEPENDS ${_p_TARGET} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET} TYPE SHARED ${_p_UNPARSED_ARGUMENTS} )
+ ecbuild_add_library_impl( TARGET ${_p_TARGET}-static TYPE STATIC ${_p_UNPARSED_ARGUMENTS} DEPENDS ${_p_TARGET} )
- set_target_properties( ${_p_TARGET}-static PROPERTIES OUTPUT_NAME ${_p_TARGET} )
+ set_target_properties( ${_p_TARGET}-static PROPERTIES OUTPUT_NAME ${_p_TARGET} )
- else()
+ else()
- ecbuild_add_library_impl( ${ARGV} )
+ ecbuild_add_library_impl( ${ARGV} )
- endif()
+ endif()
- endif()
+ endif()
- endif()
+ endif()
endmacro( ecbuild_add_library )
diff --git a/cmake/ecbuild_add_option.cmake b/cmake/ecbuild_add_option.cmake
index 85417fa..ce8c541 100644
--- a/cmake/ecbuild_add_option.cmake
+++ b/cmake/ecbuild_add_option.cmake
@@ -7,36 +7,96 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a test
+#.rst:
+#
+# ecbuild_add_option
+# ==================
+#
+# Add a CMake configuration option, which may depend on a list of packages. ::
+#
+# ecbuild_add_option( FEATURE <name>
+# [ DEFAULT ON|OFF ]
+# [ DESCRIPTION <description> ]
+# [ REQUIRED_PACKAGES <package1> [<package2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ ADVANCED ] )
+#
+# Options
+# -------
+#
+# FEATURE : required
+# name of the feature / option
+#
+# DEFAULT : optional, defaults to ON
+# if set to ON, the feature is enabled even if not explicitly requested
+#
+# DESCRIPTION : optional
+# string describing the feature (shown in summary and stored in the cache)
+#
+# REQUIRED_PACKAGES : optional
+# list of packages required to be found for this feature to be enabled
+#
+# The package specification can be either ::
+#
+# <package> [ <version> ... ]
+#
+# to search for a given package with option minimum required version or ::
+#
+# PROJECT <name> [ VERSION <version> ... ]
+#
+# to search for an ecBuild project with optional minimum required version.
+#
+# CONDITION : optional
+# list of conditions, all of which must evaluate to true for this option to
+# be enabled
+#
+# ADVANCED : optional
+# mark the feature as advanced
+#
+# Usage
+# -----
+#
+# Features with ``DEFAULT OFF`` need to be explcitly enabled by the user with
+# ``-DENABLE_<FEATURE>=ON``. If a feature is enabled, all ``REQUIRED_PACKAGES``
+# are found and every ``CONDITION`` is met, ecBuild sets the variable
+# ``HAVE_<FEATURE>`` to ``ON``. This is the variable to use to check for the
+# availability of the feature.
+#
+# If a feature is explicitly enabled but the required packages are not found,
+# configuration fails. This only applies when configuring from *clean cache*.
+# With an already populated cache, use ``-DENABLE_<FEATURE>=REQUIRE`` to make
+# the feature a required feature (this cannot be done via the CMake GUI).
+#
##############################################################################
macro( ecbuild_add_option )
- set( options ADVANCED )
+ set( options ADVANCED )
set( single_value_args FEATURE DEFAULT DESCRIPTION )
set( multi_value_args REQUIRED_PACKAGES CONDITION )
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
if( _p_UNPARSED_ARGUMENTS )
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_option(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_add_option(): \"${_p_UNPARSED_ARGUMENTS}\"")
endif()
- # check FEATURE parameter
+ # check FEATURE parameter
if( NOT _p_FEATURE )
- message(FATAL_ERROR "The call to ecbuild_add_option() doesn't specify the FEATURE.")
+ message(FATAL_ERROR "The call to ecbuild_add_option() doesn't specify the FEATURE.")
endif()
- # check DEFAULT parameter
+ # check DEFAULT parameter
if( NOT DEFINED _p_DEFAULT )
- set( _p_DEFAULT ON )
+ set( _p_DEFAULT ON )
else()
- if( NOT _p_DEFAULT MATCHES "[Oo][Nn]" AND NOT _p_DEFAULT MATCHES "[Oo][Ff][Ff]" )
- message(FATAL_ERROR "In macro ecbuild_add_option(), DEFAULT is either ON or OFF: \"${_p_DEFAULT}\"")
- endif()
- endif()
+ if( NOT _p_DEFAULT MATCHES "[Oo][Nn]" AND NOT _p_DEFAULT MATCHES "[Oo][Ff][Ff]" )
+ message(FATAL_ERROR "In macro ecbuild_add_option(), DEFAULT is either ON or OFF: \"${_p_DEFAULT}\"")
+ endif()
+ endif()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): defaults to ${_p_DEFAULT}")
# check CONDITION parameter
if( DEFINED _p_CONDITION )
@@ -47,33 +107,44 @@ macro( ecbuild_add_option )
endforeach()
file( APPEND ${_feature_condition_file} " )\n set(_${_p_FEATURE}_condition TRUE)\n else()\n set(_${_p_FEATURE}_condition FALSE)\n endif()\n")
include( ${_feature_condition_file} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): checking condition ${_p_CONDITION} -> ${_${_p_FEATURE}_condition}")
else()
set( _${_p_FEATURE}_condition TRUE )
endif()
- # check if user provided value
+ # check if user provided value
- get_property( _in_cache CACHE ENABLE_${_p_FEATURE} PROPERTY VALUE )
+ get_property( _in_cache CACHE ENABLE_${_p_FEATURE} PROPERTY VALUE )
- if( NOT "${ENABLE_${_p_FEATURE}}" STREQUAL "" AND _in_cache )
- set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" )
- else()
- set( ${_p_FEATURE}_user_provided_input 0 CACHE BOOL "" )
- endif()
+ # A feature set to REQUIRE is always treated as explicitly enabled
+ if( ENABLE_${_p_FEATURE} MATCHES "REQUIRE" )
+ set( ENABLE_${_p_FEATURE} ON CACHE BOOL "" FORCE )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} was required")
+ set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" FORCE )
+ elseif( NOT "${ENABLE_${_p_FEATURE}}" STREQUAL "" AND _in_cache )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} was found in cache")
+ set( ${_p_FEATURE}_user_provided_input 1 CACHE BOOL "" )
+ else()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} not found in cache")
+ set( ${_p_FEATURE}_user_provided_input 0 CACHE BOOL "" )
+ endif()
- mark_as_advanced( ${_p_FEATURE}_user_provided_input )
+ mark_as_advanced( ${_p_FEATURE}_user_provided_input )
- # define the option -- for cmake GUI
+ # define the option -- for cmake GUI
- option( ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}" ${_p_DEFAULT} )
+ option( ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}" ${_p_DEFAULT} )
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED ${_p_DEFAULT} PURPOSE "${_p_DESCRIPTION}" )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ENABLE_${_p_FEATURE} = ${ENABLE_${_p_FEATURE}}")
set( _do_search ${ENABLE_${_p_FEATURE}} )
if( _p_FEATURE STREQUAL "OMP" )
set( _do_search TRUE )
endif()
if( _do_search )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature enabled")
set( HAVE_${_p_FEATURE} 1 )
@@ -81,7 +152,9 @@ macro( ecbuild_add_option )
### search for dependent packages
+ set( _failed_to_find_packages ) # clear variable
foreach( pkg ${_p_REQUIRED_PACKAGES} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for dependent package ${pkg}")
string(REPLACE " " ";" pkglist ${pkg}) # string to list
@@ -102,17 +175,23 @@ macro( ecbuild_add_option )
string( TOLOWER ${pkgname} pkgLOWER )
if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): ${pkgname} has already been found")
set( ${pkgname}_already_found 1 )
- else()
- ecbuild_add_extra_search_paths( ${pkgLOWER} ) # adds search paths specific to ECMWF
+ else()
if( pkgproject )
+
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for ecbuild project ${pkgname}")
ecbuild_use_package( ${pkglist} )
+
else()
+
if( pkgname STREQUAL "MPI" )
set( _find_args ${pkglist} )
list( REMOVE_ITEM _find_args "MPI" )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for MPI")
ecbuild_find_mpi( ${_find_args} )
elseif( pkgname STREQUAL "OMP" )
set( _find_args ${pkglist} )
@@ -120,15 +199,27 @@ macro( ecbuild_add_option )
if( NOT ENABLE_${_p_FEATURE} )
list( APPEND _find_args STUBS )
endif()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for OpenMP")
ecbuild_find_omp( ${_find_args} )
+ elseif( pkgname STREQUAL "Python" OR pkgname STREQUAL "PYTHON" )
+ set( _find_args ${pkglist} )
+ list( REMOVE_ITEM _find_args ${pkgname} )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for Python")
+ ecbuild_find_python( ${_find_args} )
else()
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): searching for package ${pkgname}")
find_package( ${pkglist} )
endif()
+
endif()
- # append to list of third-party libraries (to be forward to other packages )
- string( TOUPPER ${PROJECT_NAME} PNAME )
- list( APPEND ${PNAME}_TPLS ${pkgname} )
+ endif()
+
+ # if found append to list of third-party libraries (to be forward to other packages )
+ if( ${pkgname}_FOUND OR ${pkgUPPER}_FOUND OR ${pkgLOWER}_FOUND )
+
+ list( APPEND ${PROJECT_NAME_CAPS}_TPLS ${pkgname} )
+ list( REMOVE_DUPLICATES ${PROJECT_NAME_CAPS}_TPLS )
endif()
@@ -147,48 +238,50 @@ macro( ecbuild_add_option )
endif()
endforeach()
- else()
+ else( _${_p_FEATURE}_condition )
set( HAVE_${_p_FEATURE} 0 )
- endif()
+ endif( _${_p_FEATURE}_condition )
- # FINAL CHECK
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED ${HAVE_${_p_FEATURE}} )
+ # FINAL CHECK
- if( HAVE_${_p_FEATURE} )
+ if( HAVE_${_p_FEATURE} )
- message( STATUS "Feature ${_p_FEATURE} enabled" )
+ message( STATUS "Feature ${_p_FEATURE} enabled" )
- else() # if user provided input and we cannot satisfy FAIL otherwise WARN
+ else() # if user provided input and we cannot satisfy FAIL otherwise WARN
- if( ${_p_FEATURE}_user_provided_input )
+ if( ${_p_FEATURE}_user_provided_input )
if( _${_p_FEATURE}_condition )
message( FATAL_ERROR "Feature ${_p_FEATURE} cannot be enabled -- following required packages weren't found: ${_failed_to_find_packages}" )
else()
message( FATAL_ERROR "Feature ${_p_FEATURE} cannot be enabled -- following condition was not met: ${_p_CONDITION}" )
endif()
- else()
- message( STATUS "Feature ${_p_FEATURE} was not enabled (also not requested) -- following required packages weren't found: ${_failed_to_find_packages}" )
- set( ENABLE_${_p_FEATURE} OFF )
- endif()
+ else()
+ if( _${_p_FEATURE}_condition )
+ message( STATUS "Feature ${_p_FEATURE} was not enabled (also not requested) -- following condition was not met: ${_p_CONDITION}" )
+ else()
+ message( STATUS "Feature ${_p_FEATURE} was not enabled (also not requested) -- following required packages weren't found: ${_failed_to_find_packages}" )
+ endif()
+ set( ENABLE_${_p_FEATURE} OFF )
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )
+ endif()
- endif()
+ endif()
else( _do_search )
- set( HAVE_${_p_FEATURE} 0 )
+ ecbuild_debug("ecbuild_add_option(${_p_FEATURE}): feature disabled")
+ set( HAVE_${_p_FEATURE} 0 )
+ ecbuild_set_feature( ${_p_FEATURE} ENABLED OFF )
endif( _do_search )
- if( ${_p_ADVANCED} )
- mark_as_advanced( ENABLE_${_p_FEATURE} )
- else()
- add_feature_info( ${_p_FEATURE} ENABLE_${_p_FEATURE} "${_p_DESCRIPTION}")
- endif()
-
- if( HAVE_${_p_FEATURE} )
- string( TOUPPER PNAME ${PROJECT_NAME} )
- set( ${PNAME}_HAVE_${_p_FEATURE} 1 )
- set( ${PNAME}_FEATURES "${${PNAME}_FEATURES};${PNAME}_HAVE_${_p_FEATURE}" CACHE INTERNAL "" )
+ if( ${_p_ADVANCED} )
+ mark_as_advanced( ENABLE_${_p_FEATURE} )
endif()
+ set( ${PROJECT_NAME_CAPS}_HAVE_${_p_FEATURE} ${HAVE_${_p_FEATURE}} )
+
endmacro( ecbuild_add_option )
diff --git a/cmake/ecbuild_add_persistent.cmake b/cmake/ecbuild_add_persistent.cmake
index c8ef383..42788c7 100644
--- a/cmake/ecbuild_add_persistent.cmake
+++ b/cmake/ecbuild_add_persistent.cmake
@@ -7,55 +7,79 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding persistent layer object classes
+#.rst:
+#
+# ecbuild_add_persistent
+# ======================
+#
+# Add persistent layer object classes. ::
+#
+# ecbuild_add_persistent( SRC_LIST <variable>
+# FILES <file1> [<file2> ...] ]
+# [ NAMESPACE <namespace> ] )
+#
+# Options
+# -------
+#
+# SRC_LIST : required
+# CMake variable to append the generated persistent layer objects to
+#
+# FILES : required
+# list of base names of files to build persistent class information for
+#
+# The source file is expected to have a .h extension, the generated file
+# gets a .b extension.
+#
+# NAMESPACE : optional
+# C++ namespace to place the persistent class information in
+#
##############################################################################
-
+
# define the script to build the persistent class information
set( sg_perl "${CMAKE_CURRENT_LIST_DIR}/sg.pl" CACHE INTERNAL "perl script to generate persistent objects" )
macro( ecbuild_add_persistent )
- ecbuild_find_perl( REQUIRED )
+ ecbuild_find_perl( REQUIRED )
- set( options )
- set( single_value_args SRC_LIST NAMESPACE )
- set( multi_value_args FILES )
+ set( options )
+ set( single_value_args SRC_LIST NAMESPACE )
+ set( multi_value_args FILES )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_persistent(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_add_persistent(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- if( NOT _PAR_SRC_LIST )
- message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the SRC_LIST.")
- endif()
+ if( NOT _PAR_SRC_LIST )
+ message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the SRC_LIST.")
+ endif()
- if( NOT _PAR_FILES )
- message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the FILES.")
- endif()
+ if( NOT _PAR_FILES )
+ message(FATAL_ERROR "The call to ecbuild_add_persistent() doesn't specify the FILES.")
+ endif()
- foreach( file ${_PAR_FILES} )
+ foreach( file ${_PAR_FILES} )
- get_filename_component( _file_dir ${file} PATH )
- get_filename_component( _file_we ${file} NAME_WE )
+ get_filename_component( _file_dir ${file} PATH )
+ get_filename_component( _file_we ${file} NAME_WE )
+
+ set( file ${_file_we} )
+ if( _file_dir )
+ file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} )
+ set( file ${_file_dir}/${_file_we} )
+ endif()
- set( file ${_file_we} )
- if( _file_dir )
- file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} )
- set( file ${_file_dir}/${_file_we} )
- endif()
+ # debug_var(file)
- # debug_var(file)
+ add_custom_command( OUTPUT ${file}.b
+ COMMAND ${PERL_EXECUTABLE} ${sg_perl} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.h
+ ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} ${_PAR_NAMESPACE}
+ DEPENDS ${sg_perl} ${file}.h )
+ set_source_files_properties( ${file}.h PROPERTIES OBJECT_DEPENDS "${file}.b" )
+ list( APPEND ${_PAR_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/${file}.b )
- add_custom_command(
- OUTPUT ${file}.b
- COMMAND ${PERL_EXECUTABLE} ${sg_perl} ${CMAKE_CURRENT_SOURCE_DIR}/${file}.h ${CMAKE_CURRENT_BINARY_DIR}/${_file_dir} ${_PAR_NAMESPACE}
- DEPENDS ${sg_perl} ${file}.h
- )
- set_source_files_properties( ${file}.h PROPERTIES OBJECT_DEPENDS "${file}.b" )
- list( APPEND ${_PAR_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/${file}.b )
-
- endforeach()
+ endforeach()
endmacro( ecbuild_add_persistent )
diff --git a/cmake/ecbuild_add_resources.cmake b/cmake/ecbuild_add_resources.cmake
index 12f47af..83f3c7e 100644
--- a/cmake/ecbuild_add_resources.cmake
+++ b/cmake/ecbuild_add_resources.cmake
@@ -7,58 +7,52 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a resources
+#.rst:
+#
+# ecbuild_add_resources
+# =====================
+#
+# Add resources as project files but optionally exclude them from packaging. ::
+#
+# ecbuild_add_resources( TARGET <name>
+# [ SOURCES <source1> [<source2> ...] ]
+# [ SOURCES_PACK <source1> [<source2> ...] ]
+# [ SOURCES_DONT_PACK <source1> [<source2> ...] ]
+# [ PACK <file1> [<file2> ...] ]
+# [ DONT_PACK <file1> [<file2> ...] ]
+# [ DONT_PACK_DIRS <directory1> [<directory2> ...] ]
+# [ DONT_PACK_REGEX <regex1> [<regex2> ...] ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# target name (target will only be created if there are any sources)
+#
+# SOURCES : optional, alias for SOURCES_PACK
+# list of source files included when packaging
+#
+# SOURCES_PACK : optional, alias for SOURCES
+# list of source files included when packaging
+#
+# SOURCES_DONT_PACK : optional
+# list of source files excluded when packaging
+#
+# PACK : optional, priority over DONT_PACK, DONT_PACK_DIRS, DONT_PACK_REGEX
+# list of files to include when packaging
+#
+# DONT_PACK : optional
+# list of files to exclude when packaging
+#
+# DONT_PACK_DIRS : optional
+# list of directories to exclude when packaging
+#
+# DONT_PACK_REGEX : optional
+# list of regular expressions to match files and directories to exclude when
+# packaging
+#
##############################################################################
-macro( ecbuild_dont_pack )
-
- set( options )
- set( single_value_args REGEX )
- set( multi_value_args FILES DIRS )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_resources(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( NOT DEFINED _PAR_REGEX AND NOT DEFINED _PAR_FILES AND NOT DEFINED _PAR_DIRS )
- message(FATAL_ERROR "Call to ecbuild_dont_pack does not speficify any list to avoid packing.")
- endif()
-
- set( LOCAL_FILES_NOT_TO_PACK "" )
-
- # all recursive files are not to pack
- if( DEFINED _PAR_REGEX )
- file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_PAR_REGEX} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
- endif()
-
- # selected dirs not to pack
- if( DEFINED _PAR_DIRS )
- foreach( dir ${_PAR_DIRS} )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
- endforeach()
- endif()
-
- # selected files not to pack
- if( DEFINED _PAR_FILES )
- list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_FILES} )
- endif()
-
- # transform the local files to full absolute paths
- # and place them in the global list of files not to pack
- foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
- list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
- endforeach()
-
- # save cache if we added any files not to pack
- if( LOCAL_FILES_NOT_TO_PACK )
- set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
- endif()
-
-endmacro()
-
macro( ecbuild_add_resources )
set( options )
@@ -155,4 +149,3 @@ macro( ecbuild_add_resources )
endif()
endmacro( ecbuild_add_resources )
-
diff --git a/cmake/ecbuild_add_test.cmake b/cmake/ecbuild_add_test.cmake
index 44f850f..f651de9 100644
--- a/cmake/ecbuild_add_test.cmake
+++ b/cmake/ecbuild_add_test.cmake
@@ -7,309 +7,433 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a test
+#.rst:
+#
+# ecbuild_add_test
+# ================
+#
+# Add a test as a script or an executable with a given list of source files. ::
+#
+# ecbuild_add_test( [ TARGET <name> ]
+# [ SOURCES <source1> [<source2> ...] ]
+# [ COMMAND <executable> ]
+# [ TYPE EXE|SCRIPT|PYTHON ]
+# [ ARGS <argument1> [<argument2> ...] ]
+# [ RESOURCES <file1> [<file2> ...] ]
+# [ TEST_DATA <file1> [<file2> ...] ]
+# [ BOOST ]
+# [ MPI <number-of-ranks> ]
+# [ ENABLED ON|OFF ]
+# [ LIBS <library1> [<library2> ...] ]
+# [ INCLUDES <path1> [<path2> ...] ]
+# [ DEFINITIONS <definition1> [<definition2> ...] ]
+# [ PERSISTENT <file1> [<file2> ...] ]
+# [ GENERATED <file1> [<file2> ...] ]
+# [ DEPENDS <target1> [<target2> ...] ]
+# [ TEST_DEPENDS <target1> [<target2> ...] ]
+# [ CONDITION <condition1> [<condition2> ...] ]
+# [ ENVIRONMENT <variable1> [<variable2> ...] ]
+# [ WORKING_DIRECTORY <path> ]
+# [ CFLAGS <flag1> [<flag2> ...] ]
+# [ CXXFLAGS <flag1> [<flag2> ...] ]
+# [ FFLAGS <flag1> [<flag2> ...] ]
+# [ LINKER_LANGUAGE <lang> ] )
+#
+# Options
+# -------
+#
+# TARGET : either TARGET or COMMAND must be provided, unless TYPE is PYTHON
+# target name to be built
+#
+# SOURCES : required if TARGET is provided
+# list of source files to be compiled
+#
+# COMMAND : either TARGET or COMMAND must be provided, unless TYPE is PYTHON
+# command or script to execute (no executable is built)
+#
+# TYPE : optional
+# test type, one of:
+#
+# :EXE: run built executable, default if TARGET is provided
+# :SCRIPT: run command or script, default if COMMAND is provided
+# :PYTHON: run a Python script (requires the Python interpreter to be found)
+#
+# ARGS : optional
+# list of arguments to pass to TARGET or COMMAND when running the test
+#
+# RESOURCES : optional
+# list of files to copy from the test source directory to the test directory
+#
+# TEST_DATA : optional
+# list of test data files to download
+#
+# BOOST : optional
+# use the Boost Unit Test Framework
+#
+# MPI : optional
+# number of MPI tasks to use.
+#
+# If greater than 1, and MPI is not available, the test is disabled.
+#
+# ENABLED : optional
+# if set to OFF, the test is built but not enabled as a test case
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# PERSISTENT : optional
+# list of persistent layer object files
+#
+# GENERATED : optional
+# list of files to mark as generated (sets GENERATED source file property)
+#
+# DEPENDS : optional
+# list of targets to be built before this target
+#
+# TEST_DEPENDS : optional
+# list of tests to be run before this one
+#
+# CONDITION : optional
+# list of conditions, all of which must evaluate to true for this target to be built
+#
+# ENVIRONMENT : optional
+# list of environment variables to set in the test environment
+#
+# WORKING_DIRECTORY : optional
+# directory to switch to before running the test
+#
+# CFLAGS : optional
+# list of C compiler flags to use for all C source files
+#
+# CXXFLAGS : optional
+# list of C++ compiler flags to use for all C++ source files
+#
+# FFLAGS : optional
+# list of Fortran compiler flags to use for all Fortran source files
+#
+# LINKER_LANGUAGE : optional
+# sets the LINKER_LANGUAGE property on the target
+#
##############################################################################
-# Arguments:
-# TARGET : name of test
-# ENABLED [optional]: (default ON)
-# COMMAND [optional]: Run command instead of executable
-# TYPE [optional]: EXE / SCRIPT / PYTHON (default EXE)
-# MPI [optional]: number of mpi-tasks to use. If greater than 1,
-# and MPI is not available, the test is disabled
-# SOURCES: sources to be compiled
-# LIBS: Libraries needed for linking
-# INCLUDES: Extra include directories
-# DEPENDS: Add explicit dependency to other targets (for building)
-# TEST_DEPENDS: add explicity dependency on another test running before
-# ARGS: Command-line arguments to COMMAND OR TARGET
-
macro( ecbuild_add_test )
- set( options BOOST )
- set( single_value_args TARGET ENABLED COMMAND TYPE LINKER_LANGUAGE MPI WORKING_DIRECTORY )
- set( multi_value_args SOURCES LIBS INCLUDES TEST_DEPENDS DEPENDS ARGS PERSISTENT DEFINITIONS RESOURCES TEST_DATA CFLAGS CXXFLAGS FFLAGS GENERATED CONDITION ENVIRONMENT )
+ set( options BOOST )
+ set( single_value_args TARGET ENABLED COMMAND TYPE LINKER_LANGUAGE MPI WORKING_DIRECTORY )
+ set( multi_value_args SOURCES LIBS INCLUDES TEST_DEPENDS DEPENDS ARGS
+ PERSISTENT DEFINITIONS RESOURCES TEST_DATA CFLAGS
+ CXXFLAGS FFLAGS GENERATED CONDITION ENVIRONMENT )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_add_test(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_add_test(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- set( _TEST_DIR ${CMAKE_CURRENT_BINARY_DIR} )
+ set( _TEST_DIR ${CMAKE_CURRENT_BINARY_DIR} )
- # Check for MPI
- if(_PAR_MPI)
- if( (_PAR_MPI GREATER 1) AND ( (NOT HAVE_MPI) OR (NOT MPIEXEC) ) )
- set( _PAR_ENABLED 0 )
- endif()
- if( (_PAR_MPI EQUAL 1) AND (NOT HAVE_MPI) )
- set( _PAR_MPI 0 )
- endif()
+ # Check for MPI
+ if(_PAR_MPI)
+ if( (_PAR_MPI GREATER 1) AND ( (NOT HAVE_MPI) OR (NOT MPIEXEC) ) )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${_PAR_MPI} MPI ranks requested but MPI not available - disabling test")
+ set( _PAR_ENABLED 0 )
endif()
-
- # default is enabled
- if( NOT DEFINED _PAR_ENABLED )
- set( _PAR_ENABLED 1 )
+ if( (_PAR_MPI EQUAL 1) AND (NOT HAVE_MPI) )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): 1 MPI rank requested but MPI not available - disabling MPI")
+ set( _PAR_MPI 0 )
endif()
+ endif()
+ # default is enabled
+ if( NOT DEFINED _PAR_ENABLED )
+ set( _PAR_ENABLED 1 )
+ endif()
- ### check test type
- # command implies script
- if( DEFINED _PAR_COMMAND )
- set( _PAR_TYPE "SCRIPT" )
- endif()
+ ### check test type
- # default of TYPE
- if( NOT _PAR_TYPE AND DEFINED _PAR_TARGET )
- set( _PAR_TYPE "EXE" )
- if( NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a TARGET without SOURCES.")
- endif()
- endif()
+ # command implies script
+ if( DEFINED _PAR_COMMAND )
+ set( _PAR_TYPE "SCRIPT" )
+ endif()
- if( _PAR_TYPE MATCHES "PYTHON" )
- if( PYTHONINTERP_FOUND )
- set( _PAR_COMMAND ${PYTHON_EXECUTABLE} )
- else()
- message( FATAL_ERROR "Requested a python test but python interpreter not found - PYTHON_EXECUTABLE: [${PYTHON_EXECUTABLE}]" )
- endif()
+ # default of TYPE
+ if( NOT _PAR_TYPE AND DEFINED _PAR_TARGET )
+ set( _PAR_TYPE "EXE" )
+ if( NOT _PAR_SOURCES )
+ message(FATAL_ERROR "The call to ecbuild_add_test() defines a TARGET without SOURCES.")
endif()
+ endif()
- ### further checks
-
- if( NOT _PAR_TARGET AND NOT _PAR_COMMAND )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a TARGET nor a COMMAND.")
+ if( _PAR_TYPE MATCHES "PYTHON" )
+ if( PYTHONINTERP_FOUND )
+ set( _PAR_COMMAND ${PYTHON_EXECUTABLE} )
+ else()
+ message( WARNING "Requested a python test but python interpreter not found - disabling test\nPYTHON_EXECUTABLE: [${PYTHON_EXECUTABLE}]" )
+ set( _PAR_ENABLED 0 )
endif()
-
- if( NOT _PAR_COMMAND AND NOT _PAR_SOURCES )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a COMMAND nor SOURCES, so no test can be defined or built.")
+ endif()
+
+ ### further checks
+
+ if( _PAR_ENABLED AND NOT _PAR_TARGET AND NOT _PAR_COMMAND )
+ message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a TARGET nor a COMMAND.")
+ endif()
+
+ if( _PAR_ENABLED AND NOT _PAR_COMMAND AND NOT _PAR_SOURCES )
+ message(FATAL_ERROR "The call to ecbuild_add_test() defines neither a COMMAND nor SOURCES, so no test can be defined or built.")
+ endif()
+
+ if( _PAR_TYPE MATCHES "SCRIPT" AND NOT _PAR_COMMAND )
+ message(FATAL_ERROR "The call to ecbuild_add_test() defines a 'script' but doesn't specify the COMMAND.")
+ endif()
+
+ ### conditional build
+
+ if( DEFINED _PAR_CONDITION )
+ set(_target_condition_file "${_TEST_DIR}/set_${_PAR_TARGET}_condition.cmake")
+ file( WRITE ${_target_condition_file} " if( ")
+ foreach( term ${_PAR_CONDITION} )
+ file( APPEND ${_target_condition_file} " ${term}")
+ endforeach()
+ file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
+ include( ${_target_condition_file} )
+ else()
+ set( _${_PAR_TARGET}_condition TRUE )
+ endif()
+
+ # boost unit test linking to unit_test lib ?
+
+ if( _PAR_BOOST AND ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+
+ if( HAVE_BOOST_UNIT_TEST )
+ if( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ include_directories( ${ECBUILD_BOOST_HEADER_DIRS} )
+ include_directories( ${Boost_INCLUDE_DIRS} ) # temporary until we ship Boost Unit Test with ecBuild
+ else()
+ include_directories( ${ECBUILD_BOOST_HEADER_DIRS} ${Boost_INCLUDE_DIRS} )
+ endif()
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): boost unit test framework not available - not building test")
+ set( _${_PAR_TARGET}_condition FALSE )
endif()
- if( _PAR_TYPE MATCHES "SCRIPT" AND NOT _PAR_COMMAND )
- message(FATAL_ERROR "The call to ecbuild_add_test() defines a 'script' but doesn't specify the COMMAND.")
- endif()
+ endif()
- ### conditional build
+ ### enable the tests
- if( DEFINED _PAR_CONDITION )
- set(_target_condition_file "${CMAKE_CURRENT_BINARY_DIR}/set_${_PAR_TARGET}_condition.cmake")
- file( WRITE ${_target_condition_file} " if( ")
- foreach( term ${_PAR_CONDITION} )
- file( APPEND ${_target_condition_file} " ${term}")
- endforeach()
- file( APPEND ${_target_condition_file} " )\n set(_${_PAR_TARGET}_condition TRUE)\n else()\n set(_${_PAR_TARGET}_condition FALSE)\n endif()\n")
- include( ${_target_condition_file} )
- else()
- set( _${_PAR_TARGET}_condition TRUE )
+ if( ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+
+ # add resources
+
+ if( DEFINED _PAR_RESOURCES )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): copying resources ${_PAR_RESOURCES}")
+ foreach( rfile ${_PAR_RESOURCES} )
+ execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${rfile} ${_TEST_DIR} )
+ endforeach()
endif()
- # boost unit test linking to unit_test lib ?
+ # build executable
- if( _PAR_BOOST AND ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+ if( DEFINED _PAR_SOURCES )
- if( HAVE_BOOST_UNIT_TEST )
- if( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- include_directories( ${ECBUILD_BOOST_HEADER_DIRS} )
- else()
- include_directories( ${ECBUILD_BOOST_HEADER_DIRS} ${Boost_INCLUDE_DIRS} )
- endif()
- else()
- set( _${_PAR_TARGET}_condition FALSE )
- endif()
+ # add include dirs if defined
+ if( DEFINED _PAR_INCLUDES )
+ list(REMOVE_DUPLICATES _PAR_INCLUDES )
+ foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
+ if( path )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): add ${path} to include_directories")
+ include_directories( ${path} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${path} not found - not adding to include_directories")
+ endif()
+ endforeach()
+ endif()
- endif()
+ # add persistent layer files
+ if( DEFINED _PAR_PERSISTENT )
+ if( DEFINED PERSISTENT_NAMESPACE )
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
+ else()
+ ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
+ endif()
+ endif()
- ### enable the tests
+ # add the test target
- if( ENABLE_TESTS AND _${_PAR_TARGET}_condition )
+ add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
- # add resources
+ # add extra dependencies
+ if( DEFINED _PAR_DEPENDS)
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): add dependency on ${_PAR_DEPENDS}")
+ add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
+ endif()
- if( DEFINED _PAR_RESOURCES )
- foreach( rfile ${_PAR_RESOURCES} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${rfile} ${CMAKE_CURRENT_BINARY_DIR} )
+ # add the link libraries
+ if( DEFINED _PAR_LIBS )
+ list(REMOVE_DUPLICATES _PAR_LIBS )
+ list(REMOVE_ITEM _PAR_LIBS debug)
+ list(REMOVE_ITEM _PAR_LIBS optimized)
+ foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
+ if( lib )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): linking with ${lib}")
+ target_link_libraries( ${_PAR_TARGET} ${lib} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): ${lib} not found - not linking")
+ endif()
endforeach()
endif()
- # build executable
-
- if( DEFINED _PAR_SOURCES )
-
- # add include dirs if defined
- if( DEFINED _PAR_INCLUDES )
- list(REMOVE_DUPLICATES _PAR_INCLUDES )
- foreach( path ${_PAR_INCLUDES} ) # skip NOTFOUND
- if( path )
- include_directories( ${path} )
- endif()
- endforeach()
- endif()
-
- # add persistent layer files
- if( DEFINED _PAR_PERSISTENT )
- if( DEFINED PERSISTENT_NAMESPACE )
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} NAMESPACE ${PERSISTENT_NAMESPACE} )
- else()
- ecbuild_add_persistent( SRC_LIST _PAR_SOURCES FILES ${_PAR_PERSISTENT} )
- endif()
- endif()
-
- # add the test target
-
- add_executable( ${_PAR_TARGET} ${_PAR_SOURCES} )
-
- # add extra dependencies
- if( DEFINED _PAR_DEPENDS)
- add_dependencies( ${_PAR_TARGET} ${_PAR_DEPENDS} )
- endif()
-
- # add the link libraries
- if( DEFINED _PAR_LIBS )
- list(REMOVE_DUPLICATES _PAR_LIBS )
- list(REMOVE_ITEM _PAR_LIBS debug)
- list(REMOVE_ITEM _PAR_LIBS optimized)
- foreach( lib ${_PAR_LIBS} ) # skip NOTFOUND
- if( lib )
- target_link_libraries( ${_PAR_TARGET} ${lib} )
- else()
- message( WARNING "Lib ${lib} was skipped" )
- endif()
- endforeach()
- endif()
-
- # add test libraries
- if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_LINKED AND HAVE_BOOST_UNIT_TEST )
- target_link_libraries( ${_PAR_TARGET} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${Boost_TEST_EXEC_MONITOR_LIBRARY} )
- endif()
-
- # add local flags
- if( DEFINED _PAR_CFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
- endif()
- if( DEFINED _PAR_CXXFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
- endif()
- if( DEFINED _PAR_FFLAGS )
- set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
- endif()
- if( DEFINED _PAR_GENERATED )
- set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
- endif()
-
-
- # modify definitions to compilation ( -D... )
- get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
-
- if( DEFINED _PAR_DEFINITIONS )
- list( APPEND _target_defs ${_PAR_DEFINITIONS} )
- endif()
-
- if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- list( APPEND _target_defs BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
- endif()
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
-
- # set build location to local build dir
- # not the project base as defined for libs and execs
- set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )
-
- # whatever project settings are, we always build tests with the build_rpath, not the install_rpath
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
-
- # set linker language
- if( DEFINED _PAR_LINKER_LANGUAGE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
- endif()
-
- # make sure target is removed before - some problems with AIX
- get_target_property(EXE_FILENAME ${_PAR_TARGET} OUTPUT_NAME)
- add_custom_command(
- TARGET ${_PAR_TARGET}
- PRE_BUILD
- COMMAND ${CMAKE_COMMAND} -E remove ${EXE_FILENAME}
- )
-
- set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
- set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
-
- endif() # _PAR_SOURCES
-
- if( DEFINED _PAR_COMMAND AND NOT _PAR_TARGET ) # in the absence of target, we use the command as a name
- set( _PAR_TARGET ${_PAR_COMMAND} )
+ # add test libraries
+ if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_LINKED AND HAVE_BOOST_UNIT_TEST )
+ target_link_libraries( ${_PAR_TARGET} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${Boost_TEST_EXEC_MONITOR_LIBRARY} )
endif()
- # scripts dont have actual build targets
- # we build a phony target to trigger the dependencies
- if( DEFINED _PAR_COMMAND AND DEFINED _PAR_DEPENDS )
+ # filter sources
+ ecbuild_separate_sources( TARGET ${_PAR_TARGET} SOURCES ${_PAR_SOURCES} )
- add_custom_target( ${_PAR_TARGET}.x ALL COMMAND ${CMAKE_COMMAND} -E touch ${_PAR_TARGET}.x )
+ # add local flags
+ if( DEFINED _PAR_CFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use C flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_c_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CFLAGS}" )
+ endif()
+ if( DEFINED _PAR_CXXFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use C++ flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_cxx_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_CXXFLAGS}" )
+ endif()
+ if( DEFINED _PAR_FFLAGS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): use Fortran flags ${_PAR_CFLAGS}")
+ set_source_files_properties( ${${_PAR_TARGET}_f_srcs} PROPERTIES COMPILE_FLAGS "${_PAR_FFLAGS}" )
+ endif()
+ if( DEFINED _PAR_GENERATED )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): mark as generated ${_PAR_GENERATED}")
+ set_source_files_properties( ${_PAR_GENERATED} PROPERTIES GENERATED 1 )
+ endif()
- add_dependencies( ${_PAR_TARGET}.x ${_PAR_DEPENDS} )
+ # modify definitions to compilation ( -D... )
+ get_property( _target_defs TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS )
+
+ if( DEFINED _PAR_DEFINITIONS )
+ list( APPEND _target_defs ${_PAR_DEFINITIONS} )
endif()
+ if( _PAR_BOOST AND BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ list( APPEND _target_defs BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY )
+ endif()
- # define the arguments
- set( TEST_ARGS "" )
- if( DEFINED _PAR_ARGS )
- list( APPEND TEST_ARGS ${_PAR_ARGS} )
+ if( _target_defs )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): using definitions ${_target_defs}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY COMPILE_DEFINITIONS ${_target_defs} )
endif()
- # Wrap with MPIEXEC
- if( _PAR_MPI )
- if( DEFINED _PAR_COMMAND )
- set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_PAR_COMMAND} )
- else()
- set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_PAR_TARGET} )
- endif()
+ # set build location to local build dir
+ # not the project base as defined for libs and execs
+ set_property( TARGET ${_PAR_TARGET} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${_TEST_DIR} )
+
+ # whatever project settings are, we always build tests with the build_rpath, not the install_rpath
+ set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
+
+ # set linker language
+ if( DEFINED _PAR_LINKER_LANGUAGE )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): using linker language ${_PAR_LINKER_LANGUAGE}")
+ set_property( TARGET ${_PAR_TARGET} PROPERTY LINKER_LANGUAGE ${_PAR_LINKER_LANGUAGE} )
endif()
- ### define the test
+ # make sure target is removed before - some problems with AIX
+ get_target_property(EXE_FILENAME ${_PAR_TARGET} OUTPUT_NAME)
+ add_custom_command( TARGET ${_PAR_TARGET}
+ PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E remove ${EXE_FILENAME} )
- if( _PAR_ENABLED ) # we can disable and still build it but not run it with 'make tests'
+ set_property( TARGET ${_PAR_TARGET} PROPERTY SKIP_BUILD_RPATH FALSE )
+ set_property( TARGET ${_PAR_TARGET} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE )
- if( DEFINED _PAR_COMMAND )
- add_test( ${_PAR_TARGET} ${_PAR_COMMAND} ${TEST_ARGS} ${_working_dir} ) # run a command as test
- else()
- add_test( ${_PAR_TARGET} ${_PAR_TARGET} ${TEST_ARGS} ${_working_dir} ) # run the test that was generated
- endif()
+ endif() # _PAR_SOURCES
- # get test data
+ if( DEFINED _PAR_COMMAND AND NOT _PAR_TARGET ) # in the absence of target, we use the command as a name
+ set( _PAR_TARGET ${_PAR_COMMAND} )
+ endif()
- if( _PAR_TEST_DATA )
+ # scripts dont have actual build targets
+ # we build a phony target to trigger the dependencies
+ if( DEFINED _PAR_COMMAND AND DEFINED _PAR_DEPENDS )
- ecbuild_get_test_multidata( TARGET ${_PAR_TARGET}_data NAMES ${_PAR_TEST_DATA} )
+ add_custom_target( ${_PAR_TARGET}.x ALL COMMAND ${CMAKE_COMMAND} -E touch ${_PAR_TARGET}.x )
- list( APPEND _PAR_TEST_DEPENDS ${_PAR_TARGET}_data )
+ add_dependencies( ${_PAR_TARGET}.x ${_PAR_DEPENDS} )
- endif()
+ endif()
- if( DEFINED _PAR_ENVIRONMENT )
- set_property( TEST ${_PAR_TARGET} APPEND PROPERTY ENVIRONMENT "${_PAR_ENVIRONMENT}" )
- endif()
- if( DEFINED _PAR_WORKING_DIRECTORY )
- set_tests_properties( ${_PAR_TARGET} PROPERTIES WORKING_DIRECTORY "${_PAR_WORKING_DIRECTORY}")
- endif()
+ # define the arguments
+ set( TEST_ARGS "" )
+ if( DEFINED _PAR_ARGS )
+ list( APPEND TEST_ARGS ${_PAR_ARGS} )
+ endif()
- if( DEFINED _PAR_TEST_DEPENDS )
- set_property( TEST ${_PAR_TARGET} APPEND PROPERTY DEPENDS "${_PAR_TEST_DEPENDS}" )
- endif()
+ # Wrap with MPIEXEC
+ if( _PAR_MPI )
+ if( DEFINED _PAR_COMMAND )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): running as ${MPIEXEC} -n ${_PAR_MPI} ${_TEST_DIR}/${_PAR_COMMAND}")
+ set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_TEST_DIR}/${_PAR_COMMAND} )
+ else()
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): running as ${MPIEXEC} -n ${_PAR_MPI} ${_TEST_DIR}/${_PAR_TARGET}")
+ set( _PAR_COMMAND ${MPIEXEC} -n ${_PAR_MPI} ${_TEST_DIR}/${_PAR_TARGET} )
+ endif()
+ endif()
+
+ ### define the test
+
+ if( _PAR_ENABLED ) # we can disable and still build it but not run it with 'make tests'
+
+ if( DEFINED _PAR_COMMAND )
+ add_test( ${_PAR_TARGET} ${_PAR_COMMAND} ${TEST_ARGS} ${_working_dir} ) # run a command as test
+ else()
+ add_test( ${_PAR_TARGET} ${_PAR_TARGET} ${TEST_ARGS} ${_working_dir} ) # run the test that was generated
+ endif()
+ # get test data
+
+ if( _PAR_TEST_DATA )
+
+ ecbuild_get_test_multidata( TARGET ${_PAR_TARGET}_data NAMES ${_PAR_TEST_DATA} )
+
+ list( APPEND _PAR_TEST_DEPENDS ${_PAR_TARGET}_data )
+
+ endif()
+
+ if( DEFINED _PAR_ENVIRONMENT )
+ set_property( TEST ${_PAR_TARGET} APPEND PROPERTY ENVIRONMENT "${_PAR_ENVIRONMENT}" )
endif()
- # add to the overall list of tests
- list( APPEND ECBUILD_ALL_TESTS ${_PAR_TARGET} )
- list( REMOVE_DUPLICATES ECBUILD_ALL_TESTS )
- set( ECBUILD_ALL_TESTS ${ECBUILD_ALL_TESTS} CACHE INTERNAL "" )
+ if( DEFINED _PAR_WORKING_DIRECTORY )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): set working directory to ${_PAR_WORKING_DIRECTORY}")
+ set_tests_properties( ${_PAR_TARGET} PROPERTIES WORKING_DIRECTORY "${_PAR_WORKING_DIRECTORY}")
+ endif()
+
+ if( DEFINED _PAR_TEST_DEPENDS )
+ ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): set test dependencies to ${_PAR_TEST_DEPENDS}")
+ set_property( TEST ${_PAR_TARGET} APPEND PROPERTY DEPENDS "${_PAR_TEST_DEPENDS}" )
+ endif()
+
+ endif()
+
+ # add to the overall list of tests
+ list( APPEND ECBUILD_ALL_TESTS ${_PAR_TARGET} )
+ list( REMOVE_DUPLICATES ECBUILD_ALL_TESTS )
+ set( ECBUILD_ALL_TESTS ${ECBUILD_ALL_TESTS} CACHE INTERNAL "" )
- endif() # _condition
+ endif() # _condition
- # finally mark project files
- ecbuild_declare_project_files( ${_PAR_SOURCES} )
+ # finally mark project files
+ ecbuild_declare_project_files( ${_PAR_SOURCES} )
endmacro( ecbuild_add_test )
diff --git a/cmake/ecbuild_append_to_rpath.cmake b/cmake/ecbuild_append_to_rpath.cmake
index 6868e50..db1efb4 100644
--- a/cmake/ecbuild_append_to_rpath.cmake
+++ b/cmake/ecbuild_append_to_rpath.cmake
@@ -6,32 +6,46 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to append paths to rpath
-
-# if dir is absolute, it simply appends
-# if dir is relative,
-# then it will try to make it relative to the executables
-# else it will fallback to making it absolute by prepending the install path
+##############################################################################
+#.rst:
+#
+# ecbuild_append_to_rpath
+# =======================
+#
+# Append paths to the rpath. ::
+#
+# ecbuild_append_to_rpath( RPATH_DIRS )
+#
+# ``RPATH_DIRS`` is a list of directories to append to ``CMAKE_INSTALL_RPATH``.
+#
+# * If a directory is absolute, simply append it.
+# * If a directory is relative, build a platform-dependent relative path
+# (using ``@loader_path`` on Mac OSX, ``$ORIGIN`` on Linux and Solaris)
+# or fall back to making it absolute by prepending the install prefix.
+#
+##############################################################################
function( _path_append var path )
if( "${${var}}" STREQUAL "" )
set( ${var} "${path}" PARENT_SCOPE )
else()
- set( ${var} "${${var}}:${path}" PARENT_SCOPE )
+ list( FIND ${var} ${path} _found )
+ if( _found EQUAL "-1" )
+ set( ${var} "${${var}}:${path}" PARENT_SCOPE )
+ endif()
endif()
endfunction()
macro( ecbuild_append_to_rpath RPATH_DIRS )
if( NOT ${ARGC} EQUAL 1 )
- message( SEND_ERROR "ecbuild_append_to_rpath takes 1 argument")
+ message( SEND_ERROR "ecbuild_append_to_rpath takes 1 argument")
endif()
foreach( RPATH_DIR ${RPATH_DIRS} )
if( NOT ${RPATH_DIR} STREQUAL "" )
-
+
file( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR ) # sanitize the path
if( IS_ABSOLUTE ${RPATH_DIR} )
@@ -48,6 +62,7 @@ macro( ecbuild_append_to_rpath RPATH_DIRS )
set( CMAKE_INSTALL_NAME_DIR "@loader_path/${RPATH_DIR}" )
endif()
_path_append( CMAKE_INSTALL_RPATH "@loader_path/${RPATH_DIR}" )
+
set( _done 1 )
endif()
diff --git a/cmake/ecbuild_bundle.cmake b/cmake/ecbuild_bundle.cmake
index 2a75e84..2d9b779 100644
--- a/cmake/ecbuild_bundle.cmake
+++ b/cmake/ecbuild_bundle.cmake
@@ -1,15 +1,13 @@
-# Manages an external git repository
-# Usage:
-# git(DIR <directory> URL <giturl> [BRANCH <gitbranch>] [TAG <gittag>] [UPDATE] )
+# (C) Copyright 1996-2015 ECMWF.
#
-# Arguments:
-# - DIR: directory name where repo will be cloned to
-# - URL: location of origin git repository
-# - BRANCH (optional): Branch to clone
-# - TAG (optional): Tag or commit-id to checkout
-# - UPDATE (optional) : Option to try to update every cmake run
-# - NOREMOTE (optional) : Option to avoid remote operations that require network
-# changes to tags that havent been fetched might fail
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# Set policies
+include( ecbuild_policies NO_POLICY_SCOPE )
macro( debug_here VAR )
message( STATUS " >>>>> ${VAR} [${${VAR}}]")
@@ -17,222 +15,18 @@ endmacro()
include(CMakeParseArguments)
-set( ECBUILD_GIT ON CACHE BOOL "Turn on/off ecbuild_git() function" )
-
-if( ECBUILD_GIT )
-
- find_package(Git)
-
- set( ECMWF_USER $ENV{USER} CACHE STRING "ECMWF git user" )
- set( ECMWF_GIT SSH CACHE STRING "ECMWF git protocol" )
-
- set( ECMWF_GIT_SSH "ssh://git@software.ecmwf.int:7999" CACHE INTERNAL "ECMWF ssh address" )
- set( ECMWF_GIT_HTTPS "https://${ECMWF_USER}@software.ecmwf.int/stash/scm" CACHE INTERNAL "ECMWF https address" )
-
- if( ECMWF_GIT MATCHES "[Ss][Ss][Hh]" )
- set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_SSH} CACHE INTERNAL "" )
- else()
- set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_HTTPS} CACHE INTERNAL "" )
- endif()
-
-endif()
-
-macro( ecbuild_git )
-
- set( options UPDATE NOREMOTE )
- set( single_value_args PROJECT DIR URL TAG BRANCH )
- set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( DEFINED _PAR_BRANCH AND DEFINED _PAR_TAG )
- message( FATAL_ERROR "Cannot defined both BRANCH and TAG in macro ecbuild_git" )
- endif()
-
- if( _PAR_UPDATE AND _PAR_NOREMOTE )
- message( FATAL_ERROR "Cannot pass both NOREMOTE and UPDATE in macro ecbuild_git" )
- endif()
-
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
-
- if( ECBUILD_GIT )
-
- set( _needs_switch 0 )
-
- get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE )
- get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE )
-
- ### clone if no directory
-
- if( NOT EXISTS "${_PAR_DIR}" )
-
- message( STATUS "Cloning ${_PAR_PROJECT} from ${_PAR_URL} into ${_PAR_DIR}...")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${clone_args} ${_PAR_DIR} "-q"
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${PARENT_DIR}")
- if(nok)
- message(FATAL_ERROR "${_PAR_DIR} git clone failed: ${error}\n")
- endif()
- message( STATUS "${_PAR_DIR} retrieved.")
- set( _needs_switch 1 )
-
- endif()
-
- ### check current tag and sha1
-
- if( IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
- OUTPUT_VARIABLE _sha1 RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if(nok)
- message(STATUS "git rev-parse HEAD on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
- OUTPUT_VARIABLE _current_branch RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if( nok OR _current_branch STREQUAL "" )
- message(STATUS "git rev-parse --abbrev-ref HEAD on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- #message(STATUS "git describe --exact-match --abbrev=0 @ ${ABS_PAR_DIR}")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} describe --exact-match --abbrev=0
- OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
- OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
-
- if( error MATCHES "no tag exactly matches" OR error MATCHES "No names found" )
- unset( _current_tag )
- else()
- if( nok )
- message(STATUS "git describe --exact-match --abbrev=0 on ${_PAR_DIR} failed:\n ${error}")
- endif()
- endif()
-
- if( NOT _current_tag ) # try nother method
- #message(STATUS "git name-rev --tags --name-only @ ${ABS_PAR_DIR}")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} name-rev --tags --name-only ${_sha1}
- OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error OUTPUT_STRIP_TRAILING_WHITESPACE
- WORKING_DIRECTORY "${ABS_PAR_DIR}" )
- if( nok OR _current_tag STREQUAL "" )
- message(STATUS "git name-rev --tags --name-only on ${_PAR_DIR} failed:\n ${error}")
- endif()
- endif()
-
- endif()
-
- if( DEFINED _PAR_BRANCH AND NOT "${_current_branch}" STREQUAL "${_PAR_BRANCH}" )
- set( _needs_switch 1 )
- endif()
-
- if( DEFINED _PAR_TAG AND NOT "${_current_tag}" STREQUAL "${_PAR_TAG}" )
- set( _needs_switch 1 )
- endif()
-
- if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE )
-
- add_custom_target( git_update_${_PAR_PROJECT}
- COMMAND "${GIT_EXECUTABLE}" pull -q
- WORKING_DIRECTORY "${ABS_PAR_DIR}"
- COMMENT "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR}" )
-
- set( git_update_targets "git_update_${_PAR_PROJECT};${git_update_targets}" )
-
- endif()
-
- ### updates
-
- if( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- # debug_here( ABS_PAR_DIR )
- # debug_here( _sha1 )
- # debug_here( _current_branch )
- # debug_here( _current_tag )
- # debug_here( _PAR_TAG )
- # debug_here( _PAR_BRANCH )
- # debug_here( _needs_switch )
- # debug_here( _PAR_UPDATE )
-
- if( DEFINED _PAR_BRANCH )
- set ( _gitref ${_PAR_BRANCH} )
- message(STATUS "Updating ${_PAR_PROJECT} to head of BRANCH ${_PAR_BRANCH}...")
- else()
- message(STATUS "Updating ${_PAR_PROJECT} to TAG ${_PAR_TAG}...")
- set ( _gitref ${_PAR_TAG} )
- endif()
-
- # fetching latest tags and branches
-
- if( NOT _PAR_NOREMOTE )
-
- message(STATUS "git fetch --all @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" fetch --all -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git fetch --all in ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- message(STATUS "git fetch --all --tags @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" fetch --all --tags -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git fetch --all --tags in ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- else()
- message(STATUS "${_PAR_DIR} marked NOREMOTE : Skipping git fetch")
- endif()
-
- # checking out gitref
-
- message(STATUS "git checkout ${_gitref} @ ${ABS_PAR_DIR}")
- execute_process(COMMAND "${GIT_EXECUTABLE}" checkout -q "${_gitref}"
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(FATAL_ERROR "git checkout ${_gitref} on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- if( DEFINED _PAR_BRANCH AND _PAR_UPDATE ) #############################################################################
-
- execute_process(COMMAND "${GIT_EXECUTABLE}" pull -q
- RESULT_VARIABLE nok ERROR_VARIABLE error
- WORKING_DIRECTORY "${ABS_PAR_DIR}")
- if(nok)
- message(STATUS "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR} failed:\n ${error}")
- endif()
-
- endif() ####################################################################################
-
- endif( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
-
- endif( ECBUILD_GIT )
-
-endmacro()
-
-########################################################################################################################
-
-macro( ecmwf_stash )
+include(ecbuild_git)
- set( options )
- set( single_value_args STASH )
- set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- ecbuild_git( URL "${ECMWF_GIT_ADDRESS}/${_PAR_STASH}.git" ${_PAR_UNPARSED_ARGUMENTS} )
-
-endmacro()
-
-########################################################################################################################
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle_initialize
+# =========================
+#
+# Initialise the ecBuild environment for a bundle. *Must* be called *before*
+# any call to ecbuild_bundle.
+#
+##############################################################################
macro( ecbuild_bundle_initialize )
@@ -258,21 +52,105 @@ macro( ecbuild_bundle_initialize )
endmacro()
-########################################################################################################################
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle
+# ==============
+#
+# Declare a subproject to be built as part of this bundle. ::
+#
+# ecbuild_bundle( PROJECT <name>
+# STASH <repository> | GIT <giturl>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# STASH : cannot be combined with GIT, either is required
+# Stash repository in the form <project>/<repository>
+#
+# URL : cannot be combined with STASH, either is required
+# Git URL of the remote repository to clone (see ``git help clone``)
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+# Usage
+# -----
+#
+# A bundle is used to build a number of projects together. Each subproject
+# needs to be declared with a call to ecbuild_bundle, where the order of
+# projects is important and needs to respect dependencies: if project B
+# depends on project A, A should be listed before B in the bundle.
+#
+# The first time a bundle is built, the sources of all subprojects are cloned
+# into directories named according to project in the *source* tree of the
+# bundle (which means these directories should be added to ``.gitignore``).
+#
+# Subprojects are configured and built in order. Due to being added as a
+# subproject, the usual project discovery mechanism (i.e. locating and
+# importing a ``<project>-config.cmake`` file) is not used. Also there are no
+# ``<project>-config.cmake`` files being generated for individual subprojects.
+# However there *are* package-config files being generated for each library.
+#
+# To switch off a subproject when building a bundle, set the CMake variable
+# ``BUNDLE_SKIP_<PNAME>`` where ``PNAME`` is the capitalised project name.
+#
+##############################################################################
macro( ecbuild_bundle )
set( options )
- set( single_value_args PROJECT )
+ set( single_value_args PROJECT STASH GIT )
set( multi_value_args )
cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- ecmwf_stash( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} ${_PAR_UNPARSED_ARGUMENTS} )
+ string(TOUPPER "${_PAR_PROJECT}" PNAME)
+
+ if( BUNDLE_SKIP_${PNAME} )
+ message( STATUS "Skipping bundle project ${PNAME}" )
+ else()
+
+ if( _PAR_STASH )
+ ecmwf_stash( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} STASH ${_PAR_STASH} ${_PAR_UNPARSED_ARGUMENTS} )
+ elseif( _PAR_GIT )
+ ecbuild_git( PROJECT ${_PAR_PROJECT} DIR ${PROJECT_SOURCE_DIR}/${_PAR_PROJECT} URL ${_PAR_GIT} ${_PAR_UNPARSED_ARGUMENTS} )
+ endif()
- ecbuild_use_package( PROJECT ${_PAR_PROJECT} )
+ ecbuild_use_package( PROJECT ${_PAR_PROJECT} )
+ endif()
endmacro()
+##############################################################################
+#.rst:
+#
+# ecbuild_bundle_finalize
+# =======================
+#
+# Finalise the ecBuild environment for a bundle. *Must* be called *after* the
+# last call to ecbuild_bundle.
+#
+##############################################################################
+
macro( ecbuild_bundle_finalize )
add_custom_target( update DEPENDS ${git_update_targets} )
diff --git a/cmake/ecbuild_cache.cmake b/cmake/ecbuild_cache.cmake
index af12cf1..2752392 100644
--- a/cmake/ecbuild_cache.cmake
+++ b/cmake/ecbuild_cache.cmake
@@ -6,6 +6,30 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
+##############################################################################
+#.rst:
+#
+# ecBuild Cache
+# =============
+#
+# During initialisation, ecBuild introspects the compiler and operating system
+# and performs a number of checks. The result of these is written to a
+# dedicated ``ecbuild-cache.cmake`` file in the build tree. This cache may be
+# used to speed up subsequent *clean* builds i.e. those where no CMakeCache.txt
+# exists yet.
+#
+# To use the ecBuild cache, configure with ``-DECBUILD_CACHE=<cache-file>``,
+# where ``<cache-file>`` is the path to an existing ``ecbuild-cache.cmake``.
+#
+# .. note ::
+#
+# The ecBuild cache is specific to compiler *and* operating system. Do *not*
+# attempt to use a cache file created on a different machine or with a
+# different compiler!
+#
+##############################################################################
+
+# Prepare the cache and clobber any existing ecbuild-cache.cmake
macro( ecbuild_prepare_cache )
include( CheckSymbolExists )
include( CheckIncludeFiles )
@@ -16,7 +40,7 @@ macro( ecbuild_prepare_cache )
file(WRITE ${ecbuild_cache_file} "# ecbuild cache file\n\n")
endmacro()
-
+# Buffer the CMake variable var to be written to the ecBuild cache
function( ecbuild_cache_var var )
if( NOT ${var} )
set( ${var} 0 )
@@ -24,6 +48,7 @@ function( ecbuild_cache_var var )
set( ECBUILD_CACHE_BUFFER "${ECBUILD_CACHE_BUFFER}set( ${var} ${${var}} )\n" CACHE INTERNAL "Cache buffer" )
endfunction()
+# Call check_symbol_exists only if the output is not defined yet
function( ecbuild_cache_check_symbol_exists symbol includes output )
if( NOT DEFINED ${output} )
check_symbol_exists( ${symbol} ${includes} ${output} )
@@ -31,6 +56,7 @@ function( ecbuild_cache_check_symbol_exists symbol includes output )
ecbuild_cache_var( ${output} )
endfunction()
+# Call check_include_files only if the output is not defined yet
function( ecbuild_cache_check_include_files includes output )
if( NOT DEFINED ${output} )
check_include_files( ${includes} ${output} )
@@ -38,6 +64,7 @@ function( ecbuild_cache_check_include_files includes output )
ecbuild_cache_var( ${output} )
endfunction()
+# Call check_c_source_compiles only if the output is not defined yet
function( ecbuild_cache_check_c_source_compiles source output )
if( NOT DEFINED ${output} )
check_c_source_compiles( "${source}" ${output} )
@@ -45,6 +72,7 @@ function( ecbuild_cache_check_c_source_compiles source output )
ecbuild_cache_var( ${output} )
endfunction()
+# Call check_cxx_source_compiles only if the output is not defined yet
function( ecbuild_cache_check_cxx_source_compiles source output )
if( NOT DEFINED ${output} )
check_cxx_source_compiles( "${source}" ${output} )
@@ -52,6 +80,7 @@ function( ecbuild_cache_check_cxx_source_compiles source output )
ecbuild_cache_var( ${output} )
endfunction()
+# Call check_type_size only if the output is not defined yet
function( ecbuild_cache_check_type_size type output )
if( NOT DEFINED ${output} )
check_type_size( "${type}" ${output} )
@@ -59,7 +88,8 @@ function( ecbuild_cache_check_type_size type output )
ecbuild_cache_var( ${output} )
endfunction()
+# Flush the ecBuild cache to disk and reset the buffer
function( ecbuild_flush_cache )
file( APPEND ${ecbuild_cache_file} "${ECBUILD_CACHE_BUFFER}" )
set( ECBUILD_CACHE_BUFFER "" CACHE INTERNAL "Cache buffer" )
-endfunction()
\ No newline at end of file
+endfunction()
diff --git a/cmake/ecbuild_check_c_source.cmake b/cmake/ecbuild_check_c_source_return.cmake
similarity index 78%
rename from cmake/ecbuild_check_c_source.cmake
rename to cmake/ecbuild_check_c_source_return.cmake
index 12a26c1..4e670dc 100644
--- a/cmake/ecbuild_check_c_source.cmake
+++ b/cmake/ecbuild_check_c_source_return.cmake
@@ -7,7 +7,48 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro that runs the given C code and returns its output
+#.rst:
+#
+# ecbuild_check_c_source_return
+# =============================
+#
+# Compile and run a given C source code and return its output. ::
+#
+# ecbuild_check_c_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <definition1> [ <definition2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .c file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
macro( ecbuild_check_c_source_return SOURCE )
@@ -48,7 +89,7 @@ macro( ecbuild_check_c_source_return SOURCE )
if( _PAR_INCLUDES )
list( APPEND __add_incs ${_PAR_INCLUDES} )
endif()
- if( __add_incs )
+ if( __add_incs )
set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
endif()
@@ -111,51 +152,3 @@ macro( ecbuild_check_c_source_return SOURCE )
endif()
endmacro()
-
-##############################################################################
-# macro that only adds a c flag if compiler supports it
-
-macro( cmake_add_c_flags m_c_flags )
-
- set( _flags ${m_c_flags} )
-
- if( _flags AND CMAKE_C_COMPILER_LOADED )
- set( options )
- set( single_value_args BUILD NAME )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_CFLAG )
- set( N_CFLAG 0 )
- endif()
-
- math( EXPR N_CFLAG '${N_CFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- if( DEFINED _PAR_NAME )
- check_c_compiler_flag( ${_flags} ${_PAR_NAME} )
- set( _flag_ok ${${_PAR_NAME}} )
- else()
- check_c_compiler_flag( ${_flags} C_FLAG_TEST_${N_CFLAG} )
- set( _flag_ok ${C_FLAG_TEST_${N_CFLAG}} )
- endif()
- else()
- set( _flag_ok 1 )
- endif()
-
- if( _flag_ok )
- if( _PAR_BUILD )
- set( CMAKE_C_FLAGS_${_PAR_BUILD} "${CMAKE_C_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flags}" )
- # message( STATUS "C FLAG [${_flags}] added" )
- endif()
- else()
- message( WARNING "Unrecognised C flag [${_flags}] -- skipping" )
- endif()
- endif()
- unset( _flags )
- unset( _flag_ok )
-endmacro()
-
diff --git a/cmake/ecbuild_check_compiler.cmake b/cmake/ecbuild_check_compiler.cmake
index 7ac4ea0..4333abd 100644
--- a/cmake/ecbuild_check_compiler.cmake
+++ b/cmake/ecbuild_check_compiler.cmake
@@ -81,7 +81,6 @@ if( CMAKE_CXX_COMPILER_LOADED AND ENABLE_OS_TESTS )
# check for __FUNCTION__
ecbuild_cache_check_cxx_source_compiles( "#include <iostream>\nint main(int argc, char* argv[]) { std::cout << __FUNCTION__ << std::endl; }"
EC_HAVE_FUNCTION_DEF )
-
# check for c++ abi, usually present in GNU compilers
ecbuild_cache_check_cxx_source_compiles( "#include <cxxabi.h>\n int main() { char * type; int status; char * r = abi::__cxa_demangle(type, 0, 0, &status); }"
@@ -94,7 +93,7 @@ if( CMAKE_CXX_COMPILER_LOADED AND ENABLE_OS_TESTS )
# check for sstream
ecbuild_cache_check_cxx_source_compiles( "#include <sstream>\nint main() { std::stringstream s; }"
EC_HAVE_CXX_SSTREAM )
-
+
endif()
############################################################################################
@@ -102,24 +101,51 @@ endif()
if( CMAKE_COMPILER_IS_GNUCC )
- cmake_add_c_flags("-pipe") # use pipe for faster compilation
+ ecbuild_add_c_flags("-pipe") # use pipe for faster compilation
if( ENABLE_WARNINGS )
- cmake_add_c_flags("-Wall")
- cmake_add_c_flags("-pedantic")
- # cmake_add_c_flags("-Wextra")
+ ecbuild_add_c_flags("-Wall")
+ # ecbuild_add_c_flags("-pedantic")
+ # ecbuild_add_c_flags("-Wextra")
endif()
endif()
if( CMAKE_COMPILER_IS_GNUCXX )
- cmake_add_cxx_flags("-pipe") # use pipe for faster compilation
+ ecbuild_add_cxx_flags("-pipe") # use pipe for faster compilation
if( ENABLE_WARNINGS )
- cmake_add_cxx_flags("-Wall")
- # cmake_add_cxx_flags("-Wextra")
+ ecbuild_add_cxx_flags("-Wall")
+ # ecbuild_add_cxx_flags("-Wextra")
endif()
endif()
+############################################################################################
+# compiler dependent fixes
+
+# For Cray compilers add "-Wl,-Bdynamic" at very end of linker commands, in order to produce dynamic executables by default
+
+if( "${CMAKE_C_COMPILER_ID}" STREQUAL "Cray" )
+ set( CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Cray" )
+ set( CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+if( "${CMAKE_Fortran_COMPILER_ID}" STREQUAL "Cray" )
+ set(CMAKE_Fortran_LINK_EXECUTABLE "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-Bdynamic" )
+endif()
+
+############################################################################################
+# Fortran compiler specific flags
+# if( NOT HAVE_SINGLE_PRECISION )
+# if(CMAKE_Fortran_COMPILER_ID STREQUAL "PGI")
+# ecbuild_add_fortran_flags("-r8")
+# elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+# # NOTE that if we add -fdefault-real-8 then we NEED -fdefault-double-8 to avoid quadmath
+# ecbuild_add_fortran_flags("-fdefault-real-8 -fdefault-double-8")
+# endif()
+# endif()
diff --git a/cmake/ecbuild_check_cxx11.cmake b/cmake/ecbuild_check_cxx11.cmake
index ef1b24e..51c5dc6 100644
--- a/cmake/ecbuild_check_cxx11.cmake
+++ b/cmake/ecbuild_check_cxx11.cmake
@@ -6,9 +6,33 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to check for cxx11 features
-# uses macros from the project github.com/UCL/GreatCMakeCookOff
+##############################################################################
+#.rst:
+#
+# ecbuild_check_cxx11
+# ===================
+#
+# Check for C++11 features. ::
+#
+# ecbuild_check_cxx11( [ FEATURES <feature1> [ <feature2> ... ] ]
+# [ REQUIRED <feature1> [ <feature2> ... ] ]
+# [ PRINT ] )
+#
+# This function uses macros from http://github.com/UCL/GreatCMakeCookOff
+#
+# Options
+# -------
+#
+# FEATURES : optional, checks for all features if omitted
+# list of features to check for
+#
+# REQUIRED : optional
+# list of required features to check for
+#
+# PRINT : optional
+# print a summary of features check for, found and not found
+#
+##############################################################################
function( ecbuild_check_cxx11 )
@@ -28,7 +52,15 @@ function( ecbuild_check_cxx11 )
cxx11_find_all_features( ALL_FEATURES ) # list all available features to check
- if( NOT _p_FEATURES AND NOT _p_REQUIRED ) # no input, then searhc for all features
+ # Save CXX flags
+ set( CXX_FLAGS_SNASHOT ${CMAKE_CXX_FLAGS} )
+
+ # Add C++11 flags
+ include( ${ECBUILD_MACROS_DIR}/ecbuild_get_cxx11_flags.cmake )
+ ecbuild_get_cxx11_flags( CXX11_FLAGS )
+ set( CMAKE_CXX_FLAGS "${CXX11_FLAGS} ${CMAKE_CXX_FLAGS}" )
+
+ if( NOT _p_FEATURES AND NOT _p_REQUIRED ) # no input, then search for all features
cxx11_feature_check()
@@ -44,7 +76,16 @@ function( ecbuild_check_cxx11 )
endif()
- foreach( f ${ALL_FEATURES} )
+ # Restore CXX flags
+ set( CMAKE_CXX_FLAGS ${CXX_FLAGS_SNAPSHOT} )
+
+ if( _p_FEATURES OR _p_REQUIRED )
+ set( CXX11_CHECKED_FEATURES ${_p_FEATURES} ${_p_REQUIRED} )
+ else()
+ set( CXX11_CHECKED_FEATURES ${ALL_FEATURES} )
+ endif()
+
+ foreach( f ${CXX11_CHECKED_FEATURES} )
# message( "HAS_CXX11_${FEAT}" )
string( TOUPPER ${f} FEAT )
if( HAS_CXX11_${FEAT} )
@@ -54,13 +95,38 @@ function( ecbuild_check_cxx11 )
endif()
endforeach()
+ if( CXX11_CHECKED_FEATURES )
+ list( SORT CXX11_CHECKED_FEATURES )
+ endif()
+ if( CXX11_SUPPORTED_FEATURES )
+ list( SORT CXX11_SUPPORTED_FEATURES )
+ endif()
+ if( CXX11_NOT_SUPPORTED_FEATURES )
+ list( SORT CXX11_NOT_SUPPORTED_FEATURES )
+ endif()
+
+ set( CXX11_CHECKED_FEATURES ${CXX11_CHECKED_FEATURES} PARENT_SCOPE )
set( CXX11_SUPPORTED_FEATURES ${CXX11_SUPPORTED_FEATURES} PARENT_SCOPE )
set( CXX11_NOT_SUPPORTED_FEATURES ${CXX11_NOT_SUPPORTED_FEATURES} PARENT_SCOPE )
if( _p_PRINT )
+ if( CXX11_CHECKED_FEATURES )
+ join( CXX11_CHECKED_FEATURES " " CXX11_CHECKED_FEATURES_STR )
+ message( STATUS "Checked C++11 features: ${CXX11_CHECKED_FEATURES_STR}" )
+ else()
+ message( STATUS "Checked no C++11 features" )
+ endif()
if( CXX11_SUPPORTED_FEATURES )
join( CXX11_SUPPORTED_FEATURES " " CXX11_SUPPORTED_FEATURES_STR )
message( STATUS "Found C++11 features: ${CXX11_SUPPORTED_FEATURES_STR}" )
+ else()
+ message( STATUS "Found no C++11 features" )
+ endif()
+ if( CXX11_NOT_SUPPORTED_FEATURES )
+ join( CXX11_NOT_SUPPORTED_FEATURES " " CXX11_NOT_SUPPORTED_FEATURES_STR )
+ message( STATUS "Not found C++11 features: ${CXX11_NOT_SUPPORTED_FEATURES_STR}" )
+ else()
+ message( STATUS "Found all checked C++11 features" )
endif()
endif()
diff --git a/cmake/ecbuild_check_cxx_source.cmake b/cmake/ecbuild_check_cxx_source_return.cmake
similarity index 77%
rename from cmake/ecbuild_check_cxx_source.cmake
rename to cmake/ecbuild_check_cxx_source_return.cmake
index a48ae5a..df6839c 100644
--- a/cmake/ecbuild_check_cxx_source.cmake
+++ b/cmake/ecbuild_check_cxx_source_return.cmake
@@ -7,7 +7,48 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro that runs the given C++ code and returns its output
+#.rst:
+#
+# ecbuild_check_cxx_source_return
+# ===============================
+#
+# Compile and run a given C++ code and return its output. ::
+#
+# ecbuild_check_cxx_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <definition1> [ <definition2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .cxx file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
macro( ecbuild_check_cxx_source_return SOURCE )
@@ -49,7 +90,7 @@ macro( ecbuild_check_cxx_source_return SOURCE )
if( _p_INCLUDES )
list( APPEND __add_incs ${_p_INCLUDES} )
endif()
- if( __add_incs )
+ if( __add_incs )
set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES "-DINCLUDE_DIRECTORIES:STRING=${__add_incs}")
endif()
@@ -69,8 +110,8 @@ macro( ecbuild_check_cxx_source_return SOURCE )
COMPILE_OUTPUT_VARIABLE compile_OUTPUT
RUN_OUTPUT_VARIABLE run_OUTPUT )
- # debug_var( ${_p_VAR}_COMPILED )
- # debug_var( ${_p_VAR}_EXITCODE )
+ # debug_var( ${_p_VAR}_COMPILED )
+ # debug_var( ${_p_VAR}_EXITCODE )
# if it did not compile make the return value fail code of 1
@@ -120,41 +161,3 @@ macro( ecbuild_check_cxx_source_return SOURCE )
endif()
endmacro()
-
-##############################################################################
-# macro that only adds a cxx flag if compiler supports it
-
-macro( cmake_add_cxx_flags m_cxx_flags )
-
- set( _flags ${m_cxx_flags} )
- if( _flags AND CMAKE_CXX_COMPILER_LOADED )
- set( options )
- set( single_value_args BUILD )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_CXXFLAG )
- set( N_CXXFLAG 0 )
- endif()
-
- math( EXPR N_CXXFLAG '${N_CXXFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- check_cxx_compiler_flag( ${_flags} CXX_FLAG_TEST_${N_CXXFLAG} )
- endif()
-
- if( CXX_FLAG_TEST_${N_CXXFLAG} OR ECBUILD_TRUST_FLAGS )
- if( _PAR_BUILD )
- set( CMAKE_CXX_FLAGS_${_PAR_BUILD} "${CMAKE_CXX_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flags}" )
- # message( STATUS "C++ FLAG [${_flags}] added" )
- endif()
- else()
- message( STATUS "Unrecognised CXX flag [${_flags}] -- skipping" )
- endif()
- endif()
- unset( _flags )
-
-endmacro()
diff --git a/cmake/ecbuild_check_fortran_source.cmake b/cmake/ecbuild_check_fortran_source_return.cmake
similarity index 79%
rename from cmake/ecbuild_check_fortran_source.cmake
rename to cmake/ecbuild_check_fortran_source_return.cmake
index da04a70..689749b 100644
--- a/cmake/ecbuild_check_fortran_source.cmake
+++ b/cmake/ecbuild_check_fortran_source_return.cmake
@@ -7,7 +7,48 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro that runs the given Fortran code and returns its output
+#.rst:
+#
+# ecbuild_check_fortran_source_return
+# ===================================
+#
+# Compile and run a given Fortran code and return its output. ::
+#
+# ecbuild_check_fortran_source_return( <source>
+# VAR <name>
+# OUTPUT <name>
+# [ INCLUDES <path1> [ <path2> ... ] ]
+# [ LIBS <library1> [ <library2> ... ] ]
+# [ DEFINITIONS <def1> [ <def2> ... ] ] )
+#
+# Options
+# -------
+#
+# VAR : required
+# name of the check and name of the CMake variable to write result to
+#
+# OUTPUT : required
+# name of CMake variable to write the output to
+#
+# INCLUDES : optional
+# list of paths to add to include directories
+#
+# LIBS : optional
+# list of libraries to link against (CMake targets or external libraries)
+#
+# DEFINITIONS : optional
+# list of definitions to add to preprocessor defines
+#
+# Usage
+# -----
+#
+# This will write the given source to a .f file and compile and run it with
+# try_run. If successful, ``${VAR}`` is set to 1 and ``${OUTPUT}`` is set to
+# the output of the successful run in the CMake cache.
+#
+# The check will not run if ``${VAR}`` is defined (e.g. from ecBuild cache).
+#
+##############################################################################
macro( ecbuild_check_fortran_source_return SOURCE )
@@ -112,46 +153,3 @@ macro( ecbuild_check_fortran_source_return SOURCE )
endif()
endmacro()
-
-##############################################################################
-# macro that only adds a Fortran flag if compiler supports it
-
-include( CheckFortranCompilerFlag )
-macro( cmake_add_fortran_flags m_fortran_flags )
-
- set( _flags ${m_fortran_flags} )
-
- if( _flags AND CMAKE_Fortran_COMPILER_LOADED )
-
- set( options )
- set( single_value_args BUILD )
- set( multi_value_args )
-
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
-
- if( NOT DEFINED N_FortranFLAG )
- set( N_FortranFLAG 0 )
- endif()
-
- math( EXPR N_FortranFLAG '${N_FortranFLAG}+1' )
-
- if( NOT ECBUILD_TRUST_FLAGS )
- check_fortran_compiler_flag( ${_flags} Fortran_FLAG_TEST_${N_FortranFLAG} )
- endif()
-
- if( Fortran_FLAG_TEST_${N_FortranFLAG} OR ECBUILD_TRUST_FLAGS )
- if( _PAR_BUILD )
- set( CMAKE_Fortran_FLAGS_${_PAR_BUILD} "${CMAKE_Fortran_FLAGS_${_PAR_BUILD}} ${_flags}" )
- else()
- set( CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${_flags}" )
- # message( STATUS "Fortran FLAG [${_flags}] added" )
- endif()
- else()
- message( STATUS "Unrecognised Fortran flag [${_flags}] -- skipping" )
- endif()
- endif()
-
- unset( _flags )
-
-endmacro()
-
diff --git a/cmake/ecbuild_check_functions.cmake b/cmake/ecbuild_check_functions.cmake
index e859432..0369797 100644
--- a/cmake/ecbuild_check_functions.cmake
+++ b/cmake/ecbuild_check_functions.cmake
@@ -1,5 +1,5 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
@@ -10,7 +10,7 @@
# os capability checks
if( ENABLE_OS_FUNCTIONS_TEST )
-
+
### symbol checks ##################
ecbuild_cache_check_symbol_exists( fseek "stdio.h" EC_HAVE_FSEEK )
@@ -22,17 +22,17 @@ if( ENABLE_OS_FUNCTIONS_TEST )
ecbuild_cache_check_symbol_exists( fopen "stdio.h" EC_HAVE_FOPEN )
ecbuild_cache_check_symbol_exists( flock "sys/file.h" EC_HAVE_FLOCK )
ecbuild_cache_check_symbol_exists( mmap "sys/mman.h" EC_HAVE_MMAP )
-
+
ecbuild_cache_check_symbol_exists( posix_memalign "stdlib.h" EC_HAVE_POSIX_MEMALIGN )
-
+
ecbuild_cache_check_symbol_exists( F_GETLK "fcntl.h" EC_HAVE_F_GETLK )
ecbuild_cache_check_symbol_exists( F_SETLK "fcntl.h" EC_HAVE_F_SETLK )
ecbuild_cache_check_symbol_exists( F_SETLKW "fcntl.h" EC_HAVE_F_SETLKW )
-
+
ecbuild_cache_check_symbol_exists( F_GETLK64 "fcntl.h" EC_HAVE_F_GETLK64 )
ecbuild_cache_check_symbol_exists( F_SETLK64 "fcntl.h" EC_HAVE_F_SETLK64 )
ecbuild_cache_check_symbol_exists( F_SETLKW64 "fcntl.h" EC_HAVE_F_SETLKW64 )
-
+
ecbuild_cache_check_symbol_exists( MAP_ANONYMOUS "sys/mman.h" EC_HAVE_MAP_ANONYMOUS )
ecbuild_cache_check_symbol_exists( MAP_ANON "sys/mman.h" EC_HAVE_MAP_ANON )
@@ -48,7 +48,7 @@ if( ENABLE_OS_FUNCTIONS_TEST )
ecbuild_cache_check_include_files( sys/types.h EC_HAVE_SYS_TYPES_H )
ecbuild_cache_check_include_files( malloc.h EC_HAVE_MALLOC_H )
ecbuild_cache_check_include_files( sys/malloc.h EC_HAVE_SYS_MALLOC_H )
-
+
ecbuild_cache_check_include_files( sys/param.h EC_HAVE_SYS_PARAM_H )
ecbuild_cache_check_include_files( sys/mount.h EC_HAVE_SYS_MOUNT_H )
ecbuild_cache_check_include_files( sys/vfs.h EC_HAVE_SYS_VFS_H )
@@ -93,7 +93,7 @@ if( ENABLE_OS_FUNCTIONS_TEST )
ecbuild_cache_check_c_source_compiles( "#include <sys/statvfs.h>\nint main(){ struct statvfs v; }" EC_HAVE_STRUCT_STATVFS )
# test for struct statvfs64
ecbuild_cache_check_c_source_compiles( "#define _LARGEFILE64_SOURCE\n#include <sys/statvfs.h>\nint main(){ struct statvfs64 v; }" EC_HAVE_STRUCT_STATVFS64 )
-
+
# test for fsync
ecbuild_cache_check_symbol_exists(fsync "unistd.h" EC_HAVE_FSYNC)
# test for fdatasync
@@ -106,7 +106,7 @@ if( ENABLE_OS_FUNCTIONS_TEST )
ecbuild_cache_check_c_source_compiles( "#include <sys/procfs.h>\nint main(){ return 0; }\n" EC_HAVE_SYSPROCFS )
# test for backtrace
ecbuild_cache_check_c_source_compiles( "#include <unistd.h>\n#include <execinfo.h>\n int main(){ void ** buffer; int i = backtrace(buffer, 256); }\n" EC_HAVE_EXECINFO_BACKTRACE )
-
+
#### reentrant funtions support #############
# test for gmtime_r
@@ -120,6 +120,53 @@ if( ENABLE_OS_FUNCTIONS_TEST )
# test for gethostbyname_r
ecbuild_cache_check_c_source_compiles( "#include <netdb.h>\nint main(){ const char *name; struct hostent *ret; char *buf; struct hostent **result; size_t buflen; int *h_errnop; int i = gethostbyname_r(name,ret,buf,buflen,result,h_errnop); }\n" EC_HAVE_GETHOSTBYNAME_R )
+ #### special compiler __atributes__ #############
+
+ # test for __attribute__ ((__constructor__)) -- usually present in GCC, Clang, Intel on Linux, Solaris, MacOSX; not present in AIX XLC
+ ecbuild_cache_check_c_source_compiles( "#include <stdio.h>\nstatic int argc_;static char** argv_;static char** envp_;\nint main(){printf(\"%d\", argc_);}\n__attribute__ ((__constructor__)) static void before_main(int argc, char* argv[], char* envp[]){argc_ = argc;argv_ = argv;envp_ = envp;}\n" EC_HAVE_ATTRIBUTE_CONSTRUCTOR )
+
+ if( NOT DEFINED EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV )
+ ecbuild_check_c_source_return("
+ #include <stdio.h>
+ #include <string.h>
+ int main(){return 0;}
+ __attribute__ ((__constructor__))
+ static void before_main(int argc, char* argv[], char* envp[])
+ {
+ printf(\"%d:%d\",argc, strstr(argv[0],\"cmTryCompileExec\")?1:0);
+ }"
+ VAR EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV
+ OUTPUT EC_ATTRIBUTE_CONSTRUCTOR_INITS_OUTPUT )
+
+ if( EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV AND NOT EC_ATTRIBUTE_CONSTRUCTOR_INITS_OUTPUT STREQUAL "1:1" )
+ set(EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV 0 CACHE INTERNAL "ATTRIBUTE_CONSTRUCTOR doesnt init argv correctly")
+ endif()
+ endif()
+ ecbuild_cache_var( EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV )
+
+
+ #### check for some Linux stuff #############
+
+ if( NOT DEFINED EC_HAVE_PROCFS )
+ ecbuild_check_c_source_return("
+ #include <sys/types.h>
+ #include <dirent.h>
+ int main()
+ {
+ DIR* d = opendir(\"/proc\");
+ if(d)
+ return 0;
+ else
+ return -1;
+ }"
+ VAR EC_HAVE_PROCFS
+ OUTPUT EC_HAVE_PROCFS_OUTPUT )
+ endif()
+ ecbuild_cache_var( EC_HAVE_PROCFS )
+
+# debug_var(EC_HAVE_PROCFS)
+# debug_var(EC_HAVE_PROCFS_OUTPUT)
+
endif()
diff --git a/cmake/ecbuild_check_os.cmake b/cmake/ecbuild_check_os.cmake
index 8373c4a..c9fd199 100644
--- a/cmake/ecbuild_check_os.cmake
+++ b/cmake/ecbuild_check_os.cmake
@@ -181,6 +181,30 @@ if( ENABLE_OS_ENDINESS_TEST )
endif()
############################################################################################
+# enable profiling
+
+if( ENABLE_PROFILING )
+
+ if( CMAKE_C_COMPILER_ID MATCHES "GNU" )
+
+ set( _flags "-pg;-fprofile-arcs;-ftest-coverage" )
+ ecbuild_add_c_flags( "${_flags}" )
+ ecbuild_add_cxx_flags( "${_flags}" )
+ ecbuild_add_fortran_flags( "${_flags}" )
+
+ set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_flags}" )
+ set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_flags}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${_flags}" )
+
+ unset( _flags )
+
+ else()
+ message( WARNING "Profiling enabled but ecbuild doesn't know how to enable for this particular compiler ${CMAKE_C_COMPILER_ID}")
+ endif()
+
+endif()
+
+############################################################################################
# check operating system
set( EC_OS_NAME "UNKNOWN" )
@@ -237,78 +261,78 @@ if( UNIX )
if( CMAKE_COMPILER_IS_GNUCC )
if( EC_OS_BITS EQUAL "64" )
- cmake_add_c_flags("-maix64")
+ ecbuild_add_c_flags("-maix64")
endif()
if( EC_OS_BITS EQUAL "32" )
- cmake_add_c_flags("-maix32")
+ ecbuild_add_c_flags("-maix32")
endif()
endif()
if( CMAKE_COMPILER_IS_GNUCXX )
if( EC_OS_BITS EQUAL "64" )
- cmake_add_cxx_flags("-maix64")
+ ecbuild_add_cxx_flags("-maix64")
endif()
if( EC_OS_BITS EQUAL "32" )
- cmake_add_cxx_flags("-maix32")
+ ecbuild_add_cxx_flags("-maix32")
endif()
endif()
if( CMAKE_C_COMPILER_ID MATCHES "XL" )
- cmake_add_c_flags("-qpic=large")
-# cmake_add_c_flags("-qweaksymbol")
+ ecbuild_add_c_flags("-qpic=large")
+# ecbuild_add_c_flags("-qweaksymbol")
if(EC_OS_BITS EQUAL "32" )
- cmake_add_c_flags("-q32")
+ ecbuild_add_c_flags("-q32")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
- cmake_add_c_flags("-qstrict")
- cmake_add_c_flags("-qinline")
+ ecbuild_add_c_flags("-qstrict")
+ ecbuild_add_c_flags("-qinline")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
- cmake_add_c_flags("-qfullpath")
- cmake_add_c_flags("-qkeepparm")
+ ecbuild_add_c_flags("-qfullpath")
+ ecbuild_add_c_flags("-qkeepparm")
endif()
endif()
if( CMAKE_CXX_COMPILER_ID MATCHES "XL" )
- cmake_add_cxx_flags("-qpic=large")
- cmake_add_cxx_flags("-bmaxdata:0x40000000")
- cmake_add_cxx_flags("-qrtti")
- cmake_add_cxx_flags("-qfuncsect")
+ ecbuild_add_cxx_flags("-qpic=large")
+ ecbuild_add_cxx_flags("-bmaxdata:0x40000000")
+ ecbuild_add_cxx_flags("-qrtti")
+ ecbuild_add_cxx_flags("-qfuncsect")
-# cmake_add_cxx_flags("-qweaksymbol")
+# ecbuild_add_cxx_flags("-qweaksymbol")
if(EC_OS_BITS EQUAL "32" )
- cmake_add_cxx_flags("-q32")
+ ecbuild_add_cxx_flags("-q32")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Release" OR ${CMAKE_BUILD_TYPE} MATCHES "Production" )
- cmake_add_cxx_flags("-qstrict")
- cmake_add_cxx_flags("-qinline")
+ ecbuild_add_cxx_flags("-qstrict")
+ ecbuild_add_cxx_flags("-qinline")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
- cmake_add_cxx_flags("-qfullpath")
- cmake_add_cxx_flags("-qkeepparm")
+ ecbuild_add_cxx_flags("-qfullpath")
+ ecbuild_add_cxx_flags("-qkeepparm")
endif()
endif()
if( CMAKE_Fortran_COMPILER_ID MATCHES "XL" )
- cmake_add_fortran_flags("-qxflag=dealloc_cfptr")
- cmake_add_fortran_flags("-qextname")
- cmake_add_fortran_flags("-qdpc=e")
- cmake_add_fortran_flags("-bmaxdata:0x40000000")
- cmake_add_fortran_flags("-bloadmap:loadmap -bmap:loadmap")
+ ecbuild_add_fortran_flags("-qxflag=dealloc_cfptr")
+ ecbuild_add_fortran_flags("-qextname")
+ ecbuild_add_fortran_flags("-qdpc=e")
+ ecbuild_add_fortran_flags("-bmaxdata:0x40000000")
+ ecbuild_add_fortran_flags("-bloadmap:loadmap -bmap:loadmap")
if(EC_OS_BITS EQUAL "32" )
- cmake_add_fortran_flags("-q32")
+ ecbuild_add_fortran_flags("-q32")
endif()
endif()
@@ -338,5 +362,3 @@ if( ${EC_OS_NAME} MATCHES "UNKNOWN" )
endif()
endif()
-
-
diff --git a/cmake/ecbuild_config.h.in b/cmake/ecbuild_config.h.in
index 8e68a8e..68d31f8 100644
--- a/cmake/ecbuild_config.h.in
+++ b/cmake/ecbuild_config.h.in
@@ -11,6 +11,15 @@
#ifndef @PROJECT_NAME at _ecbuild_config_h
#define @PROJECT_NAME at _ecbuild_config_h
+/* ecbuild info */
+
+#ifndef ECBUILD_VERSION_STR
+#define ECBUILD_VERSION_STR "@ECBUILD_VERSION_STR@"
+#endif
+#ifndef ECBUILD_MACROS_DIR
+#define ECBUILD_MACROS_DIR "@ECBUILD_MACROS_DIR@"
+#endif
+
/* cpu arch info */
#cmakedefine EC_BIG_ENDIAN @EC_BIG_ENDIAN@
@@ -112,6 +121,12 @@
#cmakedefine EC_HAVE_READDIR_R
#cmakedefine EC_HAVE_GETHOSTBYNAME_R
+/* --- compiler __attribute__ support --- */
+
+#cmakedefine EC_HAVE_ATTRIBUTE_CONSTRUCTOR
+#cmakedefine EC_ATTRIBUTE_CONSTRUCTOR_INITS_ARGV
+#cmakedefine EC_HAVE_PROCFS
+
/* --- c compiler support --- */
#cmakedefine EC_HAVE_C_INLINE
@@ -149,6 +164,16 @@
#define @PNAME at _CXX_COMPILER "@CMAKE_CXX_COMPILER@"
#define @PNAME at _CXX_FLAGS "@EC_CXX_FLAGS@"
+/* Needed for finding per package config files */
+
+#define @PNAME at _INSTALL_DIR "@CMAKE_INSTALL_PREFIX@"
+#define @PNAME at _INSTALL_BIN_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_BIN_DIR@"
+#define @PNAME at _INSTALL_LIB_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_LIB_DIR@"
+#define @PNAME at _INSTALL_DATA_DIR "@CMAKE_INSTALL_PREFIX@/@INSTALL_DATA_DIR@"
+
+#define @PNAME at _DEVELOPER_SRC_DIR "@CMAKE_SOURCE_DIR@"
+#define @PNAME at _DEVELOPER_BIN_DIR "@CMAKE_BINARY_DIR@"
+
#cmakedefine EC_HAVE_FORTRAN
#ifdef EC_HAVE_FORTRAN
diff --git a/cmake/ecbuild_debug_var.cmake b/cmake/ecbuild_debug_var.cmake
index 63a5104..7084c7c 100644
--- a/cmake/ecbuild_debug_var.cmake
+++ b/cmake/ecbuild_debug_var.cmake
@@ -25,6 +25,18 @@ macro( debug_var VAR )
endmacro( debug_var )
##############################################################################
+# macro for debugging a cmake list
+
+macro( debug_list VAR )
+
+ message( STATUS "${VAR}:" )
+ foreach( _elem ${${VAR}} )
+ message( STATUS " ${_elem}" )
+ endforeach()
+
+endmacro( debug_list )
+
+##############################################################################
# macro for debugging a environment variable within cmake
macro( debug_env_var VAR )
diff --git a/cmake/ecbuild_declare_project.cmake b/cmake/ecbuild_declare_project.cmake
index 57dd1b0..bc99de4 100644
--- a/cmake/ecbuild_declare_project.cmake
+++ b/cmake/ecbuild_declare_project.cmake
@@ -6,146 +6,188 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-# macro to initialize a project
+##############################################################################
+#.rst:
+#
+# ecbuild_declare_project
+# =======================
+#
+# Initialise an ecBuild project. A CMake project must have previously been
+# declared with ``project( <name> ... )``. ::
+#
+# ecbuild_declare_project()
+#
+# Sets the following CMake variables
+# (where ``PNAME`` is the capitalised project name):
+#
+# :<PNAME>_GIT_SHA1: Git revision (if project is a Git repo)
+# :<PNAME>_GIT_SHA1_SHORT: short Git revision (if project is a Git repo)
+# :<PNAME>_VERSION: version in format ``MAJOR.MINOR.PATCH``
+# :<PNAME>_VERSION_STR: version as given in ``VERSION.cmake`` or 0.0.0
+# :<PNAME>_MAJOR_VERSION: major version number
+# :<PNAME>_MINOR_VERSION: minor version number
+# :<PNAME>_PATCH_VERSION: patch version number
+# :INSTALL_BIN_DIR: relative install directory for executables
+# (default: ``bin``)
+# :INSTALL_LIB_DIR: relative install directory for libraries
+# (default: ``lib``)
+# :INSTALL_INCLUDE_DIR: relative install directory for include files
+# (default: ``include``)
+# :INSTALL_DATA_DIR: relative install directory for data
+# (default: ``share/<project_name>``)
+# :INSTALL_CMAKE_DIR: relative install directory for CMake files
+# (default: ``share/<project_name>/cmake``)
+#
+# The relative installation directories of components can be customised by
+# setting the following CMake variables on the command line or in cache:
+#
+# :<PNAME>_INSTALL_BIN_DIR: directory for installing executables
+# :<PNAME>_INSTALL_LIB_DIR: directory for installing libraries
+# :<PNAME>_INSTALL_INCLUDE_DIR: directory for installing include files
+# :<PNAME>_INSTALL_DATA_DIR: directory for installing data
+# :<PNAME>_INSTALL_CMAKE_DIR: directory for installing CMake files
+#
+# Using *relative* paths is recommended, which are interpreted relative to the
+# ``CMAKE_INSTALL_PREFIX``. Using absolute paths makes the build
+# non-relocatable and may break the generation of relocatable binary packages.
+#
+##############################################################################
macro( ecbuild_declare_project )
- string( TOUPPER ${PROJECT_NAME} PNAME )
+ string( TOUPPER ${PROJECT_NAME} PNAME )
- # reset the lists of targets (executables, libs, tests & resources)
+ # reset the lists of targets (executables, libs, tests & resources)
- set( ${PROJECT_NAME}_ALL_EXES "" CACHE INTERNAL "" )
- set( ${PROJECT_NAME}_ALL_LIBS "" CACHE INTERNAL "" )
+ set( ${PROJECT_NAME}_ALL_EXES "" CACHE INTERNAL "" )
+ set( ${PROJECT_NAME}_ALL_LIBS "" CACHE INTERNAL "" )
- # if git project get its HEAD SHA1
- # leave it here so we may use ${PNAME}_GIT_SHA1 on the version file
+ # if git project get its HEAD SHA1
+ # leave it here so we may use ${PNAME}_GIT_SHA1 on the version file
- if( EXISTS ${PROJECT_SOURCE_DIR}/.git )
- get_git_head_revision( GIT_REFSPEC ${PNAME}_GIT_SHA1 )
- if( ${PNAME}_GIT_SHA1 )
- string( SUBSTRING "${${PNAME}_GIT_SHA1}" 0 7 ${PNAME}_GIT_SHA1_SHORT )
-# debug_var( ${PNAME}_GIT_SHA1 )
-# debug_var( ${PNAME}_GIT_SHA1_SHORT )
- else()
- message( STATUS "Could not get git-sha1 for project ${PNAME}")
- endif()
- endif()
+ if( EXISTS ${PROJECT_SOURCE_DIR}/.git )
+ get_git_head_revision( GIT_REFSPEC ${PNAME}_GIT_SHA1 )
+ if( ${PNAME}_GIT_SHA1 )
+ string( SUBSTRING "${${PNAME}_GIT_SHA1}" 0 7 ${PNAME}_GIT_SHA1_SHORT )
+ # debug_var( ${PNAME}_GIT_SHA1 )
+ # debug_var( ${PNAME}_GIT_SHA1_SHORT )
+ else()
+ message( STATUS "Could not get git-sha1 for project ${PNAME}")
+ endif()
+ endif()
- # read and parse project version file
- if( EXISTS ${PROJECT_SOURCE_DIR}/VERSION.cmake )
- include( ${PROJECT_SOURCE_DIR}/VERSION.cmake )
- else()
- set( ${PROJECT_NAME}_VERSION_STR "0.0.0" )
- endif()
+ # read and parse project version file
+ if( EXISTS ${PROJECT_SOURCE_DIR}/VERSION.cmake )
+ include( ${PROJECT_SOURCE_DIR}/VERSION.cmake )
+ else()
+ set( ${PROJECT_NAME}_VERSION_STR "0.0.0" )
+ endif()
- string( REPLACE "." " " _version_list ${${PROJECT_NAME}_VERSION_STR} ) # dots to spaces
+ string( REPLACE "." " " _version_list ${${PROJECT_NAME}_VERSION_STR} ) # dots to spaces
- separate_arguments( _version_list )
+ separate_arguments( _version_list )
- list( GET _version_list 0 ${PNAME}_MAJOR_VERSION )
- list( GET _version_list 1 ${PNAME}_MINOR_VERSION )
- list( GET _version_list 2 ${PNAME}_PATCH_VERSION )
+ list( GET _version_list 0 ${PNAME}_MAJOR_VERSION )
+ list( GET _version_list 1 ${PNAME}_MINOR_VERSION )
+ list( GET _version_list 2 ${PNAME}_PATCH_VERSION )
- # cleanup patch version of any extra qualifiers ( -dev -rc1 ... )
+ # cleanup patch version of any extra qualifiers ( -dev -rc1 ... )
- string( REGEX REPLACE "^([0-9]+).*" "\\1" ${PNAME}_PATCH_VERSION "${${PNAME}_PATCH_VERSION}" )
+ string( REGEX REPLACE "^([0-9]+).*" "\\1" ${PNAME}_PATCH_VERSION "${${PNAME}_PATCH_VERSION}" )
- set( ${PNAME}_VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}.${${PNAME}_PATCH_VERSION}" CACHE INTERNAL "package ${PNAME} version" )
+ set( ${PNAME}_VERSION "${${PNAME}_MAJOR_VERSION}.${${PNAME}_MINOR_VERSION}.${${PNAME}_PATCH_VERSION}"
+ CACHE INTERNAL "package ${PNAME} version" )
- set( ${PNAME}_VERSION_STR "${${PROJECT_NAME}_VERSION_STR}" CACHE INTERNAL "package ${PNAME} version string" ) # ignore caps
+ set( ${PNAME}_VERSION_STR "${${PROJECT_NAME}_VERSION_STR}"
+ CACHE INTERNAL "package ${PNAME} version string" ) # ignore caps
-# debug_var( ${PNAME}_VERSION )
-# debug_var( ${PNAME}_VERSION_STR )
-# debug_var( ${PNAME}_MAJOR_VERSION )
-# debug_var( ${PNAME}_MINOR_VERSION )
-# debug_var( ${PNAME}_PATCH_VERSION )
+ # debug_var( ${PNAME}_VERSION )
+ # debug_var( ${PNAME}_VERSION_STR )
+ # debug_var( ${PNAME}_MAJOR_VERSION )
+ # debug_var( ${PNAME}_MINOR_VERSION )
+ # debug_var( ${PNAME}_PATCH_VERSION )
- # install dirs for this project
+ # install dirs for this project
- if( NOT DEFINED INSTALL_BIN_DIR )
- set( INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
- endif()
+ set( INSTALL_BIN_DIR bin )
+ set( INSTALL_LIB_DIR lib )
+ set( INSTALL_INCLUDE_DIR include )
+ set( INSTALL_DATA_DIR share/${PROJECT_NAME} )
+ set( INSTALL_CMAKE_DIR share/${PROJECT_NAME}/cmake )
- if( NOT DEFINED INSTALL_LIB_DIR )
- set( INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
- endif()
+ mark_as_advanced( INSTALL_BIN_DIR )
+ mark_as_advanced( INSTALL_LIB_DIR )
+ mark_as_advanced( INSTALL_INCLUDE_DIR )
+ mark_as_advanced( INSTALL_DATA_DIR )
+ mark_as_advanced( INSTALL_CMAKE_DIR )
- if( NOT DEFINED INSTALL_INCLUDE_DIR )
- set( INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
- endif()
+ # overrides of install dirs
- if( NOT DEFINED INSTALL_DATA_DIR )
- set( INSTALL_DATA_DIR share/${PROJECT_NAME} CACHE PATH "Installation directory for data files")
- endif()
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
+ if( ${PNAME}_INSTALL_${p}_DIR )
+ set( INSTALL_${p}_DIR ${${PNAME}_INSTALL_${p}_DIR} )
+ endif()
+ endforeach()
- if( NOT DEFINED INSTALL_CMAKE_DIR )
- set( INSTALL_CMAKE_DIR share/${PROJECT_NAME}/cmake CACHE PATH "Installation directory for CMake files")
- endif()
+ # warnings for non-relocatable projects
- mark_as_advanced( INSTALL_BIN_DIR )
- mark_as_advanced( INSTALL_LIB_DIR )
- mark_as_advanced( INSTALL_INCLUDE_DIR )
- mark_as_advanced( INSTALL_DATA_DIR )
- mark_as_advanced( INSTALL_CMAKE_DIR )
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
+ if( IS_ABSOLUTE ${INSTALL_${p}_DIR} )
+ message( WARNING "Defining INSTALL_${p}_DIR as absolute path '${INSTALL_${p}_DIR}' makes this build non-relocatable, possibly breaking the installation of RPMS and DEB packages" )
+ endif()
+ endforeach()
- # warnings for non-relocatable projects
+ # make relative paths absolute ( needed later on ) and cache them ...
+ foreach( p LIB BIN INCLUDE DATA CMAKE )
- foreach( p LIB BIN INCLUDE DATA CMAKE )
- if( IS_ABSOLUTE ${INSTALL_${p}_DIR} )
- message( WARNING "Defining INSTALL_${p}_DIR as absolute path '${INSTALL_${p}_DIR}' makes this build non-relocatable, possibly breaking the installation of RPMS and DEB packages" )
- endif()
- endforeach()
+ set( var INSTALL_${p}_DIR )
- # make relative paths absolute ( needed later on ) and cache them ...
- foreach( p LIB BIN INCLUDE DATA CMAKE )
+ if( NOT IS_ABSOLUTE "${${var}}" )
+ set( ${PNAME}_FULL_INSTALL_${p}_DIR "${CMAKE_INSTALL_PREFIX}/${${var}}"
+ CACHE INTERNAL "${PNAME} ${p} full install path" )
+ else()
+ message( WARNING "Setting an absolute path for ${VAR} in project ${PNAME}, breakes generation of relocatable binary packages (rpm,deb,...)" )
+ set( ${PNAME}_FULL_INSTALL_${p}_DIR "${${var}}"
+ CACHE INTERNAL "${PNAME} ${p} full install path" )
+ endif()
- set( var INSTALL_${p}_DIR )
+ # debug_var( ${PNAME}_FULL_INSTALL_${p}_DIR )
- if( NOT IS_ABSOLUTE "${${var}}" )
- set( ${PNAME}_FULL_INSTALL_${p}_DIR "${CMAKE_INSTALL_PREFIX}/${${var}}" CACHE INTERNAL "${PNAME} ${p} full install path" )
- else()
- message( WARNING "Setting an absolute path for ${VAR} in project ${PNAME}, breakes generation of relocatable binary packages (rpm,deb,...)" )
- set( ${PNAME}_FULL_INSTALL_${p}_DIR "${${var}}" CACHE INTERNAL "${PNAME} ${p} full install path" )
- endif()
+ endforeach()
-# debug_var( ${PNAME}_FULL_INSTALL_${p}_DIR )
+ # correctly set CMAKE_INSTALL_RPATH
- endforeach()
+ if( ENABLE_RPATHS )
- # correctly set CMAKE_INSTALL_RPATH
+ if( ENABLE_RELATIVE_RPATHS )
- if( ENABLE_RPATHS )
+ file( RELATIVE_PATH relative_rpath ${${PNAME}_FULL_INSTALL_BIN_DIR} ${${PNAME}_FULL_INSTALL_LIB_DIR} )
+ # debug_var( relative_rpath )
- if( ENABLE_RELATIVE_RPATHS )
+ ecbuild_append_to_rpath( ${relative_rpath} )
- file( RELATIVE_PATH relative_rpath ${${PNAME}_FULL_INSTALL_BIN_DIR} ${${PNAME}_FULL_INSTALL_LIB_DIR} )
- # debug_var( relative_rpath )
+ else() # make rpaths absolute
- ecbuild_append_to_rpath( ${relative_rpath} )
+ if( IS_ABSOLUTE ${INSTALL_LIB_DIR} )
+ ecbuild_append_to_rpath( "${INSTALL_LIB_DIR}" )
+ else()
+ ecbuild_append_to_rpath( "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" )
+ endif()
- else() # make rpaths absolute
+ endif()
- if( IS_ABSOLUTE ${INSTALL_LIB_DIR} )
- ecbuild_append_to_rpath( "${INSTALL_LIB_DIR}" )
- else()
- ecbuild_append_to_rpath( "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" )
- endif()
+ endif()
- endif()
-
- endif()
+ # debug_var( CMAKE_INSTALL_RPATH )
- # debug_var( CMAKE_INSTALL_RPATH )
+ # print project header
- # print project header
+ message( STATUS "---------------------------------------------------------" )
- message( STATUS "---------------------------------------------------------" )
-
- if( ${PNAME}_GIT_SHA1_SHORT )
- message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR}) [${${PNAME}_GIT_SHA1_SHORT}]" )
- else()
- message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR})" )
- endif()
+ if( ${PNAME}_GIT_SHA1_SHORT )
+ message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR}) [${${PNAME}_GIT_SHA1_SHORT}]" )
+ else()
+ message( STATUS "[${PROJECT_NAME}] (${${PNAME}_VERSION_STR})" )
+ endif()
endmacro( ecbuild_declare_project )
-
diff --git a/cmake/ecbuild_define_build_types.cmake b/cmake/ecbuild_define_build_types.cmake
index 9ec2ef0..f239f01 100644
--- a/cmake/ecbuild_define_build_types.cmake
+++ b/cmake/ecbuild_define_build_types.cmake
@@ -1,8 +1,8 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
@@ -35,8 +35,8 @@ mark_as_advanced(
CMAKE_CXX_FLAGS_PRODUCTION
CMAKE_C_FLAGS_PRODUCTION
CMAKE_EXE_LINKER_FLAGS_PRODUCTION
- CMAKE_SHARED_LINKER_FLAGS_PRODUCTION
- CMAKE_MODULE_LINKER_FLAGS_PRODUCTION )
+ CMAKE_SHARED_LINKER_FLAGS_PRODUCTION
+ CMAKE_MODULE_LINKER_FLAGS_PRODUCTION )
############################################################################################
# fixes for specific compilers
@@ -99,12 +99,39 @@ endif()
# fail if build type is not one of the defined ones
if( NOT CMAKE_BUILD_TYPE MATCHES "None" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Debug" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Bit" AND
- NOT CMAKE_BUILD_TYPE MATCHES "Production" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Debug" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Bit" AND
+ NOT CMAKE_BUILD_TYPE MATCHES "Production" AND
NOT CMAKE_BUILD_TYPE MATCHES "Release" AND
NOT CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo" )
message( FATAL_ERROR "CMAKE_BUILD_TYPE is not recognized. ${_BUILD_TYPE_MSG}" )
endif()
+############################################################################################
+# overrides of the flags per build type
+
+foreach( _btype NONE DEBUG BIT PRODUCTION RELEASE RELWITHDEBINFO )
+
+ # OVERRIDE Compiler FLAGS per language (we override because CMake forcely defines them)
+ foreach( _lang C CXX Fortran )
+ if( ECBUILD_${_lang}_FLAGS_${_btype} )
+ set( CMAKE_${_lang}_FLAGS_${_btype} ${ECBUILD_${_lang}_FLAGS_${_btype}} )
+ endif()
+ endforeach()
+
+ # OVERRIDE Linker FLAGS per object type (we override because CMake forcely defines them)
+ foreach( _obj EXE SHARED MODULE )
+ if( ECBUILD_${_obj}_LINKER_FLAGS_${_btype} )
+ set( CMAKE_${_obj}_LINKER_FLAGS_${_btype} ${ECBUILD_${_obj}_LINKER_FLAGS_${_btype}} )
+ endif()
+ endforeach()
+
+endforeach()
+
+# APPEND Linker FLAGS per language (we append because CMake typically leaves them empty)
+foreach( _lang C CXX Fortran )
+ if( ECBUILD_${_lang}_LINK_FLAGS )
+ set( CMAKE_${_lang}_LINK_FLAGS "${CMAKE_${_lang}_LINK_FLAGS} ${ECBUILD_${_lang}_LINK_FLAGS}" )
+ endif()
+endforeach()
\ No newline at end of file
diff --git a/cmake/ecbuild_define_options.cmake b/cmake/ecbuild_define_options.cmake
index a79fcf3..49cbed8 100644
--- a/cmake/ecbuild_define_options.cmake
+++ b/cmake/ecbuild_define_options.cmake
@@ -16,6 +16,8 @@ option( ENABLE_WARNINGS "enable compiler warnings"
option( ENABLE_LARGE_FILE_SUPPORT "build with large file support" ON )
+option( ENABLE_PROFILING "build with profiling support" OFF )
+
mark_as_advanced( ENABLE_LARGE_FILE_SUPPORT )
option( ENABLE_OS_TESTS "Run all OS tests" ON )
@@ -26,7 +28,7 @@ option( ENABLE_FORTRAN_C_INTERFACE "Enable Fortran/C Interface" OFF )
mark_as_advanced( ENABLE_FORTRAN_C_INTERFACE )
option( DEVELOPER_MODE "activates developer mode" OFF )
-option( CHECK_UNUSED_FILES "check for unused project files" ON )
+option( CHECK_UNUSED_FILES "check for unused project files (slow)" OFF )
mark_as_advanced( DEVELOPER_MODE )
mark_as_advanced( CHECK_UNUSED_FILES )
@@ -38,3 +40,9 @@ cmake_dependent_option( ENABLE_OS_ENDINESS_TEST "Run OS endiness tests" O
cmake_dependent_option( ENABLE_OS_FUNCTIONS_TEST "Run OS functions tests" ON "ENABLE_OS_TESTS" OFF)
mark_as_advanced( ENABLE_OS_TYPES_TEST ENABLE_OS_ENDINESS_TEST ENABLE_OS_FUNCTIONS_TEST )
+
+option( ECBUILD_USE_INCLUDE_DIRECTORIES "Forces to use global include_directories() instead of target specific. Adverse effect on PkgConfig generation." OFF )
+
+mark_as_advanced( ECBUILD_USE_INCLUDE_DIRECTORIES )
+
+set( CMAKE_NO_SYSTEM_FROM_IMPORTED ON )
diff --git a/cmake/ecbuild_define_uninstall.cmake b/cmake/ecbuild_define_uninstall.cmake
new file mode 100644
index 0000000..cc6efa9
--- /dev/null
+++ b/cmake/ecbuild_define_uninstall.cmake
@@ -0,0 +1,7 @@
+### adds uninstall target ###############
+
+configure_file(
+ "${CMAKE_CURRENT_LIST_DIR}/ecbuild_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ecbuild_uninstall.cmake" IMMEDIATE @ONLY)
+
+add_custom_target( uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/ecbuild_uninstall.cmake")
diff --git a/cmake/ecbuild_dont_pack.cmake b/cmake/ecbuild_dont_pack.cmake
new file mode 100644
index 0000000..099ee1d
--- /dev/null
+++ b/cmake/ecbuild_dont_pack.cmake
@@ -0,0 +1,82 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_dont_pack
+# =================
+#
+# Specify files and directories to exclude from packaging. ::
+#
+# ecbuild_dont_pack( [ FILES <file1> [ <file2> ... ] ]
+# [ DIRS <dir1> [ <dir2> ... ] ]
+# [ REGEX <regex> ] )
+#
+# Options
+# -------
+#
+# FILES : optional, one of FILES, DIRS, REGEX required
+# list of files to exclude from packaging
+#
+# DIRS : optional, one of FILES, DIRS, REGEX required
+# list of directories to exclude from packaging
+#
+# REGEX : optional, one of FILES, DIRS, REGEX required
+# regular expression to match files / directories to exclude from packaging
+#
+##############################################################################
+
+macro( ecbuild_dont_pack )
+
+ set( options )
+ set( single_value_args REGEX )
+ set( multi_value_args FILES DIRS )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_dont_pack(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( NOT DEFINED _PAR_REGEX AND NOT DEFINED _PAR_FILES AND NOT DEFINED _PAR_DIRS )
+ message(FATAL_ERROR "Call to ecbuild_dont_pack does not speficify any list to avoid packing.")
+ endif()
+
+ set( LOCAL_FILES_NOT_TO_PACK "" )
+
+ # all recursive files are not to pack
+ if( DEFINED _PAR_REGEX )
+ file( GLOB_RECURSE all_files_in_subdirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_PAR_REGEX} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${all_files_in_subdirs} )
+ endif()
+
+ # selected dirs not to pack
+ if( DEFINED _PAR_DIRS )
+ foreach( dir ${_PAR_DIRS} )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${dir}/ )
+ endforeach()
+ endif()
+
+ # selected files not to pack
+ if( DEFINED _PAR_FILES )
+ list( APPEND LOCAL_FILES_NOT_TO_PACK ${_PAR_FILES} )
+ endif()
+
+ # transform the local files to full absolute paths
+ # and place them in the global list of files not to pack
+ foreach( file ${LOCAL_FILES_NOT_TO_PACK} )
+ list( APPEND ECBUILD_DONT_PACK_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${file} )
+ endforeach()
+
+ # save cache if we added any files not to pack
+ if( LOCAL_FILES_NOT_TO_PACK )
+ set( ECBUILD_DONT_PACK_FILES ${ECBUILD_DONT_PACK_FILES} CACHE INTERNAL "" )
+ endif()
+
+endmacro()
diff --git a/cmake/ecbuild_download_resource.cmake b/cmake/ecbuild_download_resource.cmake
new file mode 100644
index 0000000..d313704
--- /dev/null
+++ b/cmake/ecbuild_download_resource.cmake
@@ -0,0 +1,47 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_download_resource
+# =========================
+#
+# Download a file from a given URL and save to FILE at configure time. ::
+#
+# ecbuild_download_resource( FILE URL )
+#
+# curl or wget is required (curl is preferred if available).
+#
+##############################################################################
+
+function( ecbuild_download_resource _p_OUT _p_URL )
+
+ if( NOT EXISTS ${_p_OUT} )
+
+ find_program( CURL_PROGRAM curl )
+ if( CURL_PROGRAM )
+ execute_process( COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_OUT} ${_p_URL}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE CMD_RESULT )
+ else()
+ find_program( WGET_PROGRAM wget )
+ if( WGET_PROGRAM )
+ execute_process( COMMAND ${WGET_PROGRAM} -nv -O ${_p_OUT} ${_p_URL}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE CMD_RESULT )
+ else()
+ message(FATAL_ERROR "Could not find curl or wget. Error downloading ${_p_URL}")
+ endif()
+ endif()
+
+ if(CMD_RESULT)
+ message(FATAL_ERROR "Error downloading ${_p_URL}")
+ endif()
+
+ endif()
+
+endfunction()
diff --git a/cmake/ecbuild_echo_targets.cmake b/cmake/ecbuild_echo_targets.cmake
index 015192b..ddaa2e4 100644
--- a/cmake/ecbuild_echo_targets.cmake
+++ b/cmake/ecbuild_echo_targets.cmake
@@ -1,14 +1,25 @@
+# (C) Copyright 1996-2015 ECMWF.
#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_target_property
+# ============================
+#
+# Output a given property of a given target. ::
#
-# FUNCTION ecbuild_echo_targets ( <list-of-targets> )
+# ecbuild_echo_target_property( <target> <property> )
#
-# Writes all possible target properties of the specified list-of-targets.
-# This is very useful for debugging
-#
+##############################################################################
+function(ecbuild_echo_target_property tgt prop)
-function(echo_target_property tgt prop)
-
cmake_policy(PUSH)
if( POLICY CMP0026 )
@@ -19,7 +30,7 @@ function(echo_target_property tgt prop)
get_property(v TARGET ${tgt} PROPERTY ${prop})
get_property(d TARGET ${tgt} PROPERTY ${prop} DEFINED)
get_property(s TARGET ${tgt} PROPERTY ${prop} SET)
-
+
# only produce output for values that are set
#if(s)
message("tgt='${tgt}' prop='${prop}'")
@@ -32,13 +43,25 @@ function(echo_target_property tgt prop)
cmake_policy(POP)
endfunction()
-
-function(echo_target tgt)
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_target
+# ===================
+#
+# Output all possible target properties of a given target. ::
+#
+# ecbuild_echo_target( <target> )
+#
+##############################################################################
+
+function(ecbuild_echo_target tgt)
if(NOT TARGET ${tgt})
message("There is no target named '${tgt}'")
return()
endif()
-
+
set(props
DEBUG_OUTPUT_NAME
DEBUG_POSTFIX
@@ -181,18 +204,30 @@ VS_WINRT_REFERENCES
WIN32_EXECUTABLE
XCODE_ATTRIBUTE_WHATEVER
)
-
+
message("======================== ${tgt} ========================")
foreach(p ${props})
- echo_target_property("${t}" "${p}")
+ ecbuild_echo_target_property("${t}" "${p}")
endforeach()
message("")
endfunction()
-
-
+
+##############################################################################
+#.rst:
+#
+# ecbuild_echo_targets
+# ====================
+#
+# Output all possible target properties of the specified list-of-targets.
+# This is very useful for debugging. ::
+#
+# ecbuild_echo_targets( <list-of-targets> )
+#
+##############################################################################
+
function(ecbuild_echo_targets)
set(tgts ${ARGV})
foreach(t ${tgts})
- echo_target("${t}")
+ ecbuild_echo_target("${t}")
endforeach()
-endfunction()
\ No newline at end of file
+endfunction()
diff --git a/cmake/ecbuild_enable_fortran.cmake b/cmake/ecbuild_enable_fortran.cmake
index dfb28d4..5560148 100644
--- a/cmake/ecbuild_enable_fortran.cmake
+++ b/cmake/ecbuild_enable_fortran.cmake
@@ -7,50 +7,68 @@
# does it submit to any jurisdiction.
##############################################################################
-
-# macro for enabling the fortan language
+#.rst:
+#
+# ecbuild_enable_fortran
+# ======================
+#
+# Enable the Fortran language. ::
+#
+# ecbuild_enable_fortran( [ MODULE_DIRECTORY <directory> ] [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# MODULE_DIRECTORY : optional, defaults to ``${CMAKE_BINARY_DIR}/module``
+# set the CMAKE_Fortran_MODULE_DIRECTORY
+#
+# REQUIRED : optional
+# fail if no working Fortran compiler was detected
+#
+##############################################################################
macro( ecbuild_enable_fortran )
- set( options REQUIRED )
- set( single_value_args MODULE_DIRECTORY )
- set( multi_value_args )
+ set( options REQUIRED )
+ set( single_value_args MODULE_DIRECTORY )
+ set( multi_value_args )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_enable_fortran(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_enable_fortran(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- enable_language( Fortran )
+ enable_language( Fortran )
- if( DEFINED _PAR_REQUIRED )
- if( CMAKE_Fortran_COMPILER_FORCED )
- set( CMAKE_Fortran_COMPILER_WORKS 1 )
- endif()
- if( NOT CMAKE_Fortran_COMPILER OR NOT CMAKE_Fortran_COMPILER_WORKS )
- message( FATAL_ERROR "Fortran compiler required by project ${PROJECT_NAME} but does not seem to work" )
- endif()
+ if( DEFINED _PAR_REQUIRED )
+ if( CMAKE_Fortran_COMPILER_FORCED )
+ set( CMAKE_Fortran_COMPILER_WORKS 1 )
endif()
-
- if( CMAKE_Fortran_COMPILER_LOADED )
- include(CheckFortranFunctionExists)
- if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
- include(FortranCInterface)
- endif()
- set( EC_HAVE_FORTRAN 1 )
+ if( NOT CMAKE_Fortran_COMPILER OR NOT CMAKE_Fortran_COMPILER_WORKS )
+ message( FATAL_ERROR "Fortran compiler required by project ${PROJECT_NAME} but does not seem to work" )
endif()
+ endif()
- if( DEFINED _PAR_MODULE_DIRECTORY )
- set( CMAKE_Fortran_MODULE_DIRECTORY ${_PAR_MODULE_DIRECTORY} )
- else()
- set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module CACHE PATH "directory for all fortran modules." )
+ if( CMAKE_Fortran_COMPILER_LOADED )
+ include(CheckFortranFunctionExists)
+ if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
+ include(FortranCInterface)
endif()
+ set( EC_HAVE_FORTRAN 1 )
+ endif()
+
+ if( DEFINED _PAR_MODULE_DIRECTORY )
+ set( CMAKE_Fortran_MODULE_DIRECTORY ${_PAR_MODULE_DIRECTORY} )
+ else()
+ set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module
+ CACHE PATH "directory for all fortran modules." )
+ endif()
- file( MAKE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} )
+ file( MAKE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} )
- include_directories( ${CMAKE_Fortran_MODULE_DIRECTORY} )
+ include_directories( ${CMAKE_Fortran_MODULE_DIRECTORY} )
- install( CODE "EXECUTE_PROCESS (COMMAND \"${CMAKE_COMMAND}\" -E copy_directory \"${CMAKE_Fortran_MODULE_DIRECTORY}/\${BUILD_TYPE}\" \"${INSTALL_INCLUDE_DIR}\")" )
+ install( CODE "EXECUTE_PROCESS (COMMAND \"${CMAKE_COMMAND}\" -E copy_directory \"${CMAKE_Fortran_MODULE_DIRECTORY}/\${BUILD_TYPE}\" \"${INSTALL_INCLUDE_DIR}\")" )
endmacro( ecbuild_enable_fortran )
diff --git a/cmake/ecbuild_features.cmake b/cmake/ecbuild_features.cmake
new file mode 100644
index 0000000..5d619a5
--- /dev/null
+++ b/cmake/ecbuild_features.cmake
@@ -0,0 +1,121 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+# Internal macros to handle CMake features
+
+include( FeatureSummary )
+
+function( debug_var _var )
+ message( "${_var} = ${${_var}}" )
+endfunction()
+
+# Write list of enabled features to CMake variable ${OUT}
+macro( ecbuild_enabled_features OUT )
+ get_property( ${OUT} GLOBAL PROPERTY ENABLED_FEATURES )
+endmacro()
+
+# Write list of disabled features to CMake variable ${OUT}
+macro( ecbuild_disabled_features OUT )
+ get_property( ${OUT} GLOBAL PROPERTY DISABLED_FEATURES )
+endmacro()
+
+# Enable the feature ${_name} (add to enabled features, remove from disabled)
+function( ecbuild_enable_feature _name )
+
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( _disabled_features )
+ list( REMOVE_ITEM _disabled_features ${_name} )
+ endif()
+
+ list( APPEND _enabled_features ${_name} )
+ list( REMOVE_DUPLICATES _enabled_features )
+
+ set_property(GLOBAL PROPERTY ENABLED_FEATURES "${_enabled_features}" )
+ set_property(GLOBAL PROPERTY DISABLED_FEATURES "${_disabled_features}" )
+
+endfunction()
+
+# Disable the feature ${_name} (add to disabled features, remove from enabled)
+function( ecbuild_disable_feature _name )
+
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( _enabled_features )
+ list( REMOVE_ITEM _enabled_features ${_name} )
+ endif()
+
+ list( APPEND _disabled_features ${_name} )
+ list( REMOVE_DUPLICATES _disabled_features )
+
+ set_property(GLOBAL PROPERTY ENABLED_FEATURES "${_enabled_features}" )
+ set_property(GLOBAL PROPERTY DISABLED_FEATURES "${_disabled_features}" )
+
+endfunction()
+
+# Set description of feature ${_name} to ${_desc}
+function( ecbuild_set_feature_description _name _desc)
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" )
+endfunction()
+
+# Set purpose of feature ${_name} to ${_desc}
+function( ecbuild_set_feature_purpose _name _purpose )
+ get_property( _purpose_list GLOBAL PROPERTY _CMAKE_${_name}_PURPOSE )
+ list( APPEND _purpose_list ${_purpose} )
+ list( REMOVE_DUPLICATES _purpose_list )
+ set_property(GLOBAL PROPERTY _CMAKE_${_name}_PURPOSE "${_purpose_list}" )
+endfunction()
+
+# en/disable feature ${_name} and set its description and purpose
+function( ecbuild_set_feature _name )
+
+ set(options ) # none
+ set(oneValueArgs ENABLED DESCRIPTION PURPOSE )
+ set(multiValueArgs ) # none
+
+ CMAKE_PARSE_ARGUMENTS( _PAR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ get_property( _feature_desc GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION )
+ get_property( _enabled_features GLOBAL PROPERTY ENABLED_FEATURES )
+ get_property( _disabled_features GLOBAL PROPERTY DISABLED_FEATURES )
+
+ if( DEFINED _PAR_ENABLED )
+ if( _PAR_ENABLED )
+ ecbuild_enable_feature( ${_name} )
+ else()
+ ecbuild_disable_feature( ${_name} )
+ endif()
+ endif()
+
+ ecbuild_enabled_features( _enabled_features )
+ list (FIND _enabled_features "${_name}" _index)
+ if (${_index} GREATER -1)
+ set( _feature_found 1 )
+ endif()
+
+ ecbuild_disabled_features( _disabled_features )
+ list (FIND _disabled_features "${_name}" _index)
+ if (${_index} GREATER -1)
+ set( _feature_found 1 )
+ endif()
+
+ if( NOT _feature_found )
+ message( WARNING "Feature ${_name} has not yet been enabled or disabled" )
+ endif()
+
+ if( _PAR_DESCRIPTION )
+ ecbuild_set_feature_description( ${_name} ${_PAR_DESCRIPTION} )
+ endif()
+
+ if( _PAR_PURPOSE )
+ ecbuild_set_feature_purpose( ${_name} ${_PAR_PURPOSE} )
+ endif()
+
+endfunction()
diff --git a/cmake/ecbuild_find_fortranlibs.cmake b/cmake/ecbuild_find_fortranlibs.cmake
index b40a5eb..850c4a3 100644
--- a/cmake/ecbuild_find_fortranlibs.cmake
+++ b/cmake/ecbuild_find_fortranlibs.cmake
@@ -1,131 +1,163 @@
-# (C) Copyright 1996-2014 ECMWF.
+# (C) Copyright 1996-2015 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
-# granted to it by virtue of its status as an intergovernmental organisation nor
-# does it submit to any jurisdiction.
-
-############################################################################################
-# macro to find fortran (static) link libraries
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+##############################################################################
+#.rst:
+#
+# ecbuild_find_fortranlibs
+# ========================
+#
+# Find the Fortran (static) link libraries. ::
+#
+# ecbuild_find_fortranlibs( [ COMPILER gfortran|pgi|xlf|intel ]
+# [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# COMPILER : optional, defaults to gfortran
+# request a given Fortran compiler (``gfortran``, ``pgi``, ``xlf``, ``intel``)
+#
+# REQUIRED : optional
+# fail if Fortran libraries were not found
+#
+##############################################################################
macro( ecbuild_find_fortranlibs )
- # parse parameters
+ # parse parameters
+
+ set( options REQUIRED )
+ set( single_value_args COMPILER )
+ set( multi_value_args )
+
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_find_python(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- set( options REQUIRED )
- set( single_value_args COMPILER )
- set( multi_value_args )
+ if( NOT FORTRANLIBS_FOUND ) # don't repeat search
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ if( _PAR_COMPILER )
+ set( __known_fcomp 0 )
+ endif()
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_python(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ if( _PAR_COMPILER MATCHES "gfortran" )
+ set( WITH_LIBGFORTRAN 1 )
+ set( __known_fcomp 1 )
endif()
- if( NOT FORTRANLIBS_FOUND ) # don't repeat search
+ if( _PAR_COMPILER MATCHES "pgi" )
+ set( WITH_PGI_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
- if( _PAR_COMPILER )
- set( __known_fcomp 0 )
- endif()
+ if( _PAR_COMPILER MATCHES "xlf" )
+ set( WITH_XL_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
- if( _PAR_COMPILER MATCHES "gfortran" )
- set( WITH_LIBGFORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
+ if( _PAR_COMPILER MATCHES "intel" )
+ set( WITH_INTEL_FORTRAN 1 )
+ set( __known_fcomp 1 )
+ endif()
- if( _PAR_COMPILER MATCHES "pgi" )
- set( WITH_PGI_FORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
+ if( _PAR_COMPILER AND NOT __known_fcomp )
+ message( FATAL_ERROR "unknown fortran compiler ${_PAR_COMPILER}" )
+ endif()
- if( _PAR_COMPILER MATCHES "xlf" )
- set( WITH_XL_FORTRAN 1 )
- set( __known_fcomp 1 )
- endif()
+ ### set path from environment variables
- if( _PAR_COMPILER MATCHES "intel" )
- message( FATAL_ERROR "searching for intel libraries has not been implemented" )
- set( __known_fcomp 1 )
- endif()
+ foreach( _fortran_lib PGI XLF LIBGFORTRAN INTEL )
+ if( NOT ${_fortran_lib}_PATH AND NOT "$ENV{${_fortran_lib}_PATH}" STREQUAL "" )
+ set( ${_fortran_lib}_PATH "$ENV{${_fortran_lib}_PATH}" )
+ endif()
+ endforeach()
- if( _PAR_COMPILER AND NOT __known_fcomp )
- message( FATAL_ERROR "unknown fortran compiler ${_PAR_COMPILER}" )
- endif()
+ set( _flibs_found 0 )
- ### set path from environment variables
+ ### default is to search for gfortran
- foreach( _fortran_lib PGI XLF LIBGFORTRAN )
- if( NOT ${_fortran_lib}_PATH AND NOT "$ENV{${_fortran_lib}_PATH}" STREQUAL "" )
- set( ${_fortran_lib}_PATH "$ENV{${_fortran_lib}_PATH}" )
- endif()
- endforeach()
+ if( NOT (WITH_PGI_FORTRAN OR WITH_LIBGFORTRAN OR
+ WITH_XL_FORTRAN OR WITH_INTEL_FORTRAN)
+ AND NOT (DEFINED PGI_PATH OR DEFINED LIBGFORTRAN_PATH OR
+ DEFINED XLF_PATH OR DEFINED INTEL_PATH) )
+ message( WARNING "Finding fortran libs for unspecified Fortran compiler: default search [ gfortran ]" )
+ set( WITH_LIBGFORTRAN 1 )
+ endif()
- set( _flibs_found 0 )
+ ### actual search ...
- ### default is to search for gfortran
+ if( WITH_PGI_FORTRAN OR DEFINED PGI_PATH )
- if( NOT WITH_PGI_FORTRAN AND NOT WITH_LIBGFORTRAN AND NOT WITH_XL_FORTRAN
- AND NOT DEFINED PGI_PATH AND NOT DEFINED LIBGFORTRAN_PATH AND NOT DEFINED XLF_PATH )
- message( WARNING "Finding fortran libs for unspecified Fortran compiler: default search [ gfortran ]" )
- set( WITH_LIBGFORTRAN 1 )
- endif()
+ find_package(PGIFortran)
- ### actual search ...
+ if( LIBPGIFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "PGI" )
+ endif()
- if( WITH_PGI_FORTRAN OR DEFINED PGI_PATH )
+ endif()
- find_package(PGIFortran)
+ if( WITH_LIBGFORTRAN OR DEFINED LIBGFORTRAN_PATH )
- if( LIBPGIFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${PGIFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "PGI" )
- endif()
+ find_package(LibGFortran)
- endif()
+ if( LIBGFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${GFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "gfortran" )
+ endif()
- if( WITH_LIBGFORTRAN OR DEFINED LIBGFORTRAN_PATH )
+ endif()
- find_package(LibGFortran)
+ if( WITH_XL_FORTRAN OR DEFINED XLF_PATH )
- if( LIBGFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${GFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "gfortran" )
- endif()
+ find_package(XLFortranLibs)
- endif()
+ if( LIBXLFORTRAN_FOUND )
+ set( FORTRAN_LIBRARIES ${XLFORTRAN_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "XLF" )
+ endif()
- if( WITH_XL_FORTRAN OR DEFINED XLF_PATH )
+ endif()
- find_package(XLFortranLibs)
+ if( WITH_INTEL_FORTRAN OR DEFINED INTEL_PATH )
- if( LIBXLFORTRAN_FOUND )
- set( FORTRAN_LIBRARIES ${XLFORTRAN_LIBRARIES} )
- set( _flibs_found 1 )
- set( _flibs_txt "XLF" )
- endif()
+ find_package(LibIFort)
- endif()
+ if( LIBIFORT_FOUND )
+ set( FORTRAN_LIBRARIES ${IFORT_LIBRARIES} )
+ set( _flibs_found 1 )
+ set( _flibs_txt "Intel" )
+ endif()
- ### set found
+ endif()
- if( _flibs_found )
- set( FORTRANLIBS_FOUND 1 CACHE INTERNAL "Fortran libraries found" )
- set( FORTRANLIBS_NAME ${_flibs_txt} CACHE INTERNAL "Fortran library name" )
- set( FORTRAN_LIBRARIES ${FORTRAN_LIBRARIES} CACHE INTERNAL "Fortran libraries" )
- message( STATUS "Found Fortran libraries: ${_flibs_txt}" )
- else()
- set( FORTRANLIBS_FOUND 0 )
- if( _PAR_REQUIRED )
- message( FATAL_ERROR "Failed to find Fortran libraries" )
- else()
- message( STATUS "Failed to find Fortran libraries" )
- endif()
- endif()
+ ### set found
+
+ if( _flibs_found )
+ set( FORTRANLIBS_FOUND 1 CACHE INTERNAL "Fortran libraries found" )
+ set( FORTRANLIBS_NAME ${_flibs_txt} CACHE INTERNAL "Fortran library name" )
+ set( FORTRAN_LIBRARIES ${FORTRAN_LIBRARIES} CACHE INTERNAL "Fortran libraries" )
+ message( STATUS "Found Fortran libraries: ${_flibs_txt}" )
+ else()
+ set( FORTRANLIBS_FOUND 0 )
+ if( _PAR_REQUIRED )
+ message( FATAL_ERROR "Failed to find Fortran libraries" )
+ else()
+ message( STATUS "Failed to find Fortran libraries" )
+ endif()
+ endif()
- endif( NOT FORTRANLIBS_FOUND )
+ endif( NOT FORTRANLIBS_FOUND )
endmacro( ecbuild_find_fortranlibs )
diff --git a/cmake/ecbuild_find_lexyacc.cmake b/cmake/ecbuild_find_lexyacc.cmake
index 373b81c..b74c3e1 100644
--- a/cmake/ecbuild_find_lexyacc.cmake
+++ b/cmake/ecbuild_find_lexyacc.cmake
@@ -6,55 +6,79 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to find python
-
-# OUTPUT:
+##############################################################################
+#.rst:
+#
+# ecbuild_find_lexyacc
+# ====================
+#
+# Find flex and bison (preferred) or lex and yacc.
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables can set to skip search for bison or yacc:
+#
+# :SKIP_BISON: do not search for flex and bison
+# :SKIP_YACC: do not search for lex and yacc
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if flex and bison were found:
+#
+# :FLEX_FOUND: flex was found
+# :BISON_FOUND: bison was found
+# :FLEX_EXECUTABLE: path to the flex executable
+# :BISON_EXECUTABLE: path to the bison executable
+#
+# The following CMake variables are set if lex and yacc were found:
#
-# BISON_FOUND or YACC_FOUND
-# FLEX_FOUND or LEX_FOUND
+# :LEX_FOUND: lex was found
+# :YACC_FOUND: yacc was found
+# :LEX_EXECUTABLE: path to the lex executable
+# :YACC_EXECUTABLE: path to the yacc executable
#
-# BISON_EXECUTABLE or YACC_EXECUTABLE
-# FLEX_EXECUTABLE or LEX_EXECUTABLE
+##############################################################################
macro( ecbuild_find_lexyacc )
- # find preferably bison or else yacc
+ # find preferably bison or else yacc
- if( NOT SKIP_BISON )
+ if( NOT SKIP_BISON )
- find_package( BISON 2.3 )
- find_package( FLEX )
+ find_package( BISON 2.3 )
+ find_package( FLEX )
- endif()
+ endif()
- if( NOT BISON_FOUND AND NOT SKIP_YACC )
+ if( NOT BISON_FOUND AND NOT SKIP_YACC )
- find_package( YACC )
- find_package( LEX )
+ find_package( YACC )
+ find_package( LEX )
- endif()
+ endif()
- if( NOT YACC_FOUND AND NOT BISON_FOUND ) # neither bison nor yacc were found
- message( FATAL_ERROR "neither bison or yacc were found - at least one is required (together with its lexical analyser" )
- endif()
+ if( NOT YACC_FOUND AND NOT BISON_FOUND ) # neither bison nor yacc were found
+ message( FATAL_ERROR "neither bison or yacc were found - at least one is required (together with its lexical analyser" )
+ endif()
- if( NOT YACC_FOUND ) # check for both bison & flex together
- if( BISON_FOUND AND NOT FLEX_FOUND )
- message( FATAL_ERROR "both bison and flex are required - flex not found" )
- endif()
- if( FLEX_FOUND AND NOT BISON_FOUND )
- message( FATAL_ERROR "both bison and flex are required - bison not found" )
- endif()
- endif()
+ if( NOT YACC_FOUND ) # check for both bison & flex together
+ if( BISON_FOUND AND NOT FLEX_FOUND )
+ message( FATAL_ERROR "both bison and flex are required - flex not found" )
+ endif()
+ if( FLEX_FOUND AND NOT BISON_FOUND )
+ message( FATAL_ERROR "both bison and flex are required - bison not found" )
+ endif()
+ endif()
- if( NOT BISON_FOUND ) # check for both yacc & lex together
- if( YACC_FOUND AND NOT LEX_FOUND )
- message( FATAL_ERROR "both yacc and lex are required - lex not found" )
- endif()
- if( LEX_FOUND AND NOT YACC_FOUND )
- message( FATAL_ERROR "both yacc and lex are required - yacc not found" )
- endif()
- endif()
+ if( NOT BISON_FOUND ) # check for both yacc & lex together
+ if( YACC_FOUND AND NOT LEX_FOUND )
+ message( FATAL_ERROR "both yacc and lex are required - lex not found" )
+ endif()
+ if( LEX_FOUND AND NOT YACC_FOUND )
+ message( FATAL_ERROR "both yacc and lex are required - yacc not found" )
+ endif()
+ endif()
endmacro( ecbuild_find_lexyacc )
diff --git a/cmake/ecbuild_find_mpi.cmake b/cmake/ecbuild_find_mpi.cmake
index 9ed4b3c..d3f6c8e 100644
--- a/cmake/ecbuild_find_mpi.cmake
+++ b/cmake/ecbuild_find_mpi.cmake
@@ -6,10 +6,69 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to find MPI
-# uses the canonical find_package( MPI )
-# but does more checks
+##############################################################################
+#.rst:
+#
+# ecbuild_find_mpi
+# ================
+#
+# Find MPI and check if MPI compilers successfully compile C/C++/Fortran. ::
+#
+# ecbuild_find_mpi( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if MPI was not found
+#
+# Input variables
+# ---------------
+#
+# ECBUILD_FIND_MPI : optional, defaults to TRUE
+# test C/C++/Fortran MPI compiler wrappers (assume working if FALSE)
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if MPI was found: ::
+#
+# MPI_FOUND
+# MPI_LIBRARY
+# MPI_EXTRA_LIBRARY
+#
+# The following CMake variables are set if C bindings were found: ::
+#
+# MPI_C_FOUND
+# MPI_C_COMPILER
+# MPI_C_COMPILE_FLAGS
+# MPI_C_INCLUDE_PATH
+# MPI_C_LIBRARIES
+# MPI_C_LINK_FLAGS
+#
+# The following CMake variables are set if C++ bindings were found: ::
+#
+# MPI_CXX_FOUND
+# MPI_CXX_COMPILER
+# MPI_CXX_COMPILE_FLAGS
+# MPI_CXX_INCLUDE_PATH
+# MPI_CXX_LIBRARIES
+# MPI_CXX_LINK_FLAGS
+#
+# The following CMake variables are set if Fortran bindings were found: ::
+#
+# MPI_Fortran_FOUND
+# MPI_Fortran_COMPILER
+# MPI_Fortran_COMPILE_FLAGS
+# MPI_Fortran_INCLUDE_PATH
+# MPI_Fortran_LIBRARIES
+# MPI_Fortran_LINK_FLAGS
+#
+##############################################################################
macro( ecbuild_find_mpi )
@@ -156,6 +215,32 @@ macro( ecbuild_find_mpi )
endmacro( ecbuild_find_mpi )
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_mpi
+# ==================
+#
+# Find MPI, add include directories and set compiler flags. ::
+#
+# ecbuild_enable_mpi( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ] )
+#
+# For each MPI language binding found, set the corresponding compiler flags
+# and add the include directories.
+#
+# See ``ecbuild_find_mpi`` for input and output variables.
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if MPI was not found
+#
+##############################################################################
macro( ecbuild_enable_mpi )
@@ -180,23 +265,36 @@ macro( ecbuild_enable_mpi )
endif()
if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
- cmake_add_c_flags("${MPI_C_COMPILE_FLAGS}")
+ ecbuild_add_c_flags("${MPI_C_COMPILE_FLAGS}")
include_directories(${MPI_C_INCLUDE_PATH})
endif()
if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
- cmake_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
+ ecbuild_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
include_directories(${MPI_CXX_INCLUDE_PATH})
endif()
if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
- include(ecbuild_check_fortran_source)
- cmake_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
+ include( ecbuild_check_fortran_source_return )
+ ecbuild_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
include_directories(${MPI_Fortran_INCLUDE_PATH})
endif()
endmacro( ecbuild_enable_mpi )
+##############################################################################
+#.rst:
+#
+# ecbuild_include_mpi
+# ===================
+#
+# Add MPI include directories and set compiler flags, assuming MPI was found.
+#
+# For each MPI language binding found, set corresponding compiler flags and
+# add include directories. ``ecbuild_find_mpi`` must have been called before.
+#
+##############################################################################
+
macro( ecbuild_include_mpi )
set( options )
@@ -210,20 +308,20 @@ macro( ecbuild_include_mpi )
endif()
if( MPI_C_FOUND AND NOT C_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_c_source )
- cmake_add_c_flags("${MPI_C_COMPILE_FLAGS}")
+ include( ecbuild_check_c_source_return )
+ ecbuild_add_c_flags("${MPI_C_COMPILE_FLAGS}")
include_directories(${MPI_C_INCLUDE_PATH})
endif()
if( MPI_CXX_FOUND AND NOT CXX_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_cxx_source )
- cmake_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
+ include( ecbuild_check_cxx_source_return )
+ ecbuild_add_cxx_flags("${MPI_CXX_COMPILE_FLAGS}")
include_directories(${MPI_CXX_INCLUDE_PATH})
endif()
if( MPI_Fortran_FOUND AND NOT Fortran_COMPILER_SUPPORTS_MPI )
- include( ecbuild_check_fortran_source )
- cmake_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
+ include( ecbuild_check_fortran_source_return )
+ ecbuild_add_fortran_flags("${MPI_Fortran_COMPILE_FLAGS}")
include_directories(${MPI_Fortran_INCLUDE_PATH})
endif()
diff --git a/cmake/ecbuild_find_omp.cmake b/cmake/ecbuild_find_omp.cmake
index 86ab139..2de9d74 100644
--- a/cmake/ecbuild_find_omp.cmake
+++ b/cmake/ecbuild_find_omp.cmake
@@ -7,8 +7,7 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a test
-##############################################################################
+# macro for looking for openmp flags
macro( lookup_omp_flags )
set(_OMP_FLAG_GNU "-fopenmp")
@@ -74,19 +73,47 @@ macro( lookup_omp_flags )
endmacro()
-
-# MACRO ecbuild_find_omp
+##############################################################################
+#.rst:
+#
+# ecbuild_find_omp
+# ================
+#
+# Find OpenMP. ::
+#
+# ecbuild_find_omp( [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ]
+# [ STUBS ] )
+#
+# Options
+# -------
+#
+# COMPONENTS : optional, defaults to C
+# list of required languages bindings
+#
+# REQUIRED : optional
+# fail if OpenMP was not found
+#
+# STUBS : optional
+# search for OpenMP stubs
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if OpenMP was found:
+#
+# :OMP_FOUND: OpenMP was found
+#
+# For each language listed in COMPONENTS, the following variables are set:
#
-# ecbuild_find_omp( COMPONENTS C CXX Fortran
-# STUBS )
-# Sets following variables
-# - OMP_FOUND
-# - OMP_<lang>_FOUND
-# - OMP_<lang>_FLAGS
+# :OMP_<LANG>_FOUND: OpenMP bindings for LANG were found
+# :OMP_<LANG>_FLAGS: OpenMP compiler flags for LANG
#
-# If STUBS are available, above flags will still hold TRUE,
-# as OMP code will just work.
+# If the STUBS option was given, all variables are also set with the OMPSTUBS
+# instead of the OMP prefix.
#
+##############################################################################
+
macro( ecbuild_find_omp )
set( options REQUIRED STUBS )
@@ -166,6 +193,16 @@ macro( ecbuild_find_omp )
endmacro( ecbuild_find_omp )
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_omp
+# ==================
+#
+# Find OpenMP for C, C++ and Fortran and set the compiler flags for each
+# language for which OpenMP support was detected.
+#
+##############################################################################
macro( ecbuild_enable_omp )
@@ -185,6 +222,17 @@ macro( ecbuild_enable_omp )
endmacro( ecbuild_enable_omp )
+##############################################################################
+#.rst:
+#
+# ecbuild_enable_ompstubs
+# =======================
+#
+# Find OpenMP stubs for C, C++ and Fortran and set the compiler flags for each
+# language for which OpenMP stubs were detected.
+#
+##############################################################################
+
macro( ecbuild_enable_ompstubs )
ecbuild_find_omp( COMPONENTS C CXX Fortran STUBS )
diff --git a/cmake/ecbuild_find_package.cmake b/cmake/ecbuild_find_package.cmake
index e6cea19..4d1b108 100644
--- a/cmake/ecbuild_find_package.cmake
+++ b/cmake/ecbuild_find_package.cmake
@@ -7,184 +7,319 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for adding a subproject directory
+#.rst:
+#
+# ecbuild_find_package
+# ====================
+#
+# Find a package and import its configuration. ::
+#
+# ecbuild_find_package( NAME <name>
+# [ VERSION <version> [ EXACT ] ]
+# [ COMPONENTS <component1> [ <component2> ... ] ]
+# [ REQUIRED ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# package name (used as ``Find<name>.cmake`` and ``<name>-config.cmake``)
+#
+# VERSION : optional
+# minimum required package version
+#
+# COMPONENTS : optional
+# list of package components to find (behaviour depends on the package)
+#
+# EXACT : optional, requires VERSION
+# require the exact version rather than a minimum version
+#
+# REQUIRED : optional
+# fail if package cannot be found
+#
+# QUIET : optional
+# do not output package information if found
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables influence the behaviour if set (``<name>`` is
+# the package name as given, ``<NAME>`` is the capitalised version):
+#
+# :DEVELOPER_MODE: if enabled, discover projects parallel in the build tree
+# :<name>_PATH: install prefix path of the package
+# :<NAME>_PATH: install prefix path of the package
+# :<name>_DIR: directory containing the ``<name>-config.cmake`` file
+# (usually ``<install-prefix>/share/<name>/cmake``)
+#
+# The environment variables ``<name>_PATH``, ``<NAME>_PATH``, ``<name>_DIR``
+# are taken into account only if the corresponding CMake variables are unset.
+#
+# Usage
+# -----
+#
+# The search proceeds as follows:
+#
+# 1. If any paths have been specified by the user via CMake or environment
+# variables as given above or a parallel build tree has been discovered in
+# DEVELOPER_MODE:
+#
+# * search for ``<name>-config.cmake`` in those paths only
+# * search using ``Find<name>.cmake`` (which should respect those paths)
+# * fail if the package was not found in any of those paths
+#
+# 2. Search for ``<name>-config.cmake`` in the ``CMAKE_PREFIX_PATH`` and if
+# DEVELOPER_MODE is enabled also in the user package registry.
+#
+# 3. Search system paths for ``<name>-config.cmake``.
+#
+# 4. Search system paths using ``Find<name>.cmake``.
+#
+# 5. If the package was found, and a minimum version was requested, check if
+# the version is acceptable and if not, unset ``<NAME>_FOUND``.
+#
+# 6. Fail if the package was not found and is REQUIRED.
+#
##############################################################################
macro( ecbuild_find_package )
- set( options REQUIRED QUIET EXACT )
- set( single_value_args NAME VERSION )
- set( multi_value_args )
+ set( options REQUIRED QUIET EXACT )
+ set( single_value_args NAME VERSION )
+ set( multi_value_args COMPONENTS )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_package(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_find_package(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- if( NOT _PAR_NAME )
- message(FATAL_ERROR "The call to ecbuild_find_package() doesn't specify the NAME.")
- endif()
+ if( NOT _PAR_NAME )
+ message(FATAL_ERROR "The call to ecbuild_find_package() doesn't specify the NAME.")
+ endif()
- if( _PAR_EXACT AND NOT _PAR_VERSION )
- message(FATAL_ERROR "Call to ecbuild_find_package() requests EXACT but doesn't specify VERSION.")
- endif()
+ if( _PAR_EXACT AND NOT _PAR_VERSION )
+ message(FATAL_ERROR "Call to ecbuild_find_package() requests EXACT but doesn't specify VERSION.")
+ endif()
- # debug_var( _PAR_NAME )
+ # debug_var( _PAR_NAME )
- string( TOUPPER ${_PAR_NAME} PNAME )
+ string( TOUPPER ${_PAR_NAME} pkgUPPER )
+ string( TOLOWER ${_PAR_NAME} pkgLOWER )
- set( _${PNAME}_version "" )
- if( _PAR_VERSION )
- set( _${PNAME}_version ${_PAR_VERSION} )
- if( _PAR_EXACT )
- set( _${PNAME}_version ${_PAR_VERSION} EXACT )
- endif()
+ set( _${pkgUPPER}_version "" )
+ if( _PAR_VERSION )
+ set( _${pkgUPPER}_version ${_PAR_VERSION} )
+ if( _PAR_EXACT )
+ set( _${pkgUPPER}_version ${_PAR_VERSION} EXACT )
endif()
+ endif()
+
+ # check developer mode (search in cmake cache )
+
+ if( NOT ${DEVELOPER_MODE} )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): Not in DEVELOPER_MODE - do not search package registry or recent GUI build paths")
+ set( NO_DEV_BUILD_DIRS NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_BUILDS_PATH )
+ endif()
+
+ # in DEVELOPER_MODE we give priority to projects parallel in the build tree
+ # so lets prepend a parallel build tree to the search path if we find it
+
+ if( DEVELOPER_MODE )
+ get_filename_component( _proj_bdir "${CMAKE_BINARY_DIR}/../${pkgLOWER}" ABSOLUTE )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - searching for ${pkgLOWER}-config.cmake in ${_proj_bdir}")
+ if( EXISTS ${_proj_bdir}/${pkgLOWER}-config.cmake )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - found parallel build tree in ${_proj_bdir}")
+ if( ${pkgUPPER}_PATH )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - ${pkgUPPER}_PATH already set to ${${pkgUPPER}_PATH}, not modifying")
+ else()
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): in DEVELOPER_MODE - setting ${pkgUPPER}_PATH to ${_proj_bdir}")
+ set( ${pkgUPPER}_PATH "${_proj_bdir}" )
+ endif()
+ endif()
+ endif()
- # check developer mode (search in cmake cache )
-
- if( NOT ${DEVELOPER_MODE} )
- set( NO_DEV_BUILD_DIRS NO_CMAKE_PACKAGE_REGISTRY NO_CMAKE_BUILDS_PATH )
- endif()
-
- # search user defined paths first
-
- if( ${_PAR_NAME}_PATH OR ${PNAME}_PATH OR ${_PAR_NAME}_DIR OR ${PNAME}_DIR )
-
- # debug_var( ${_PAR_NAME}_PATH )
- # debug_var( ${PNAME}_PATH )
+ # Read environment variables but ONLY if the corresponding CMake variables are unset
- # 1) search using CONFIG mode -- try to locate a configuration file provided by the package (package-config.cmake)
+ if( NOT DEFINED ${pkgUPPER}_PATH AND NOT "$ENV{${pkgUPPER}_PATH}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${pkgUPPER}_PATH=${${pkgUPPER}_PATH} from environment")
+ set( ${pkgUPPER}_PATH "$ENV{${pkgUPPER}_PATH}" )
+ endif()
- if( NOT ${_PAR_NAME}_FOUND )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} NO_MODULE QUIET
- HINTS ${${PNAME}_PATH} ${_PAR_NAME}_PATH ${${PNAME}_DIR} ${${_PAR_NAME}_DIR}
- NO_DEFAULT_PATH )
- endif()
+ if( NOT DEFINED ${_PAR_NAME}_PATH AND NOT "$ENV{${_PAR_NAME}_PATH}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH} from environment")
+ set( ${_PAR_NAME}_PATH "$ENV{${_PAR_NAME}_PATH}" )
+ endif()
- # 2) search using a file Find<package>.cmake if it exists ( macro should itself take *_PATH into account )
+ if( NOT DEFINED ${_PAR_NAME}_DIR AND NOT "$ENV{${_PAR_NAME}_DIR}" STREQUAL "" )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): setting ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR} from environment")
+ set( ${_PAR_NAME}_DIR "$ENV{${_PAR_NAME}_DIR}" )
+ endif()
- if( NOT ${_PAR_NAME}_FOUND )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} MODULE QUIET )
- endif()
+ # Find packages quietly unless in DEVELOPER_MODE, LOG_LEVEL is DEBUG or the package is REQUIRED
- # is <package>_PATH was given and we don't find anything then we FAIL
+ if( NOT ( DEVELOPER_MODE OR _PAR_REQUIRED ) AND ( ECBUILD_LOG_LEVEL GREATER ${ECBUILD_DEBUG} ) )
+ set( _find_quiet QUIET )
+ endif()
- if( NOT ${_PAR_NAME}_FOUND )
- if( ${_PAR_NAME}_PATH )
- message( FATAL_ERROR "${_PAR_NAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
- endif()
- if( ${PNAME}_PATH )
- message( FATAL_ERROR "${PNAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
- endif()
- endif()
+ # search user defined paths first
- endif()
+ if( ${_PAR_NAME}_PATH OR ${pkgUPPER}_PATH OR ${_PAR_NAME}_DIR )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH}, ${pkgUPPER}_PATH=${${pkgUPPER}_PATH}, ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR}")
- # 3) search developer cache and recently configured packages in the CMake GUI
+ # 1) search using CONFIG mode -- try to locate a configuration file provided by the package (package-config.cmake)
- if( NOT ${_PAR_NAME}_FOUND )
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 1) search using CONFIG mode -- try to locate ${_PAR_NAME}-config.cmake")
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): using hints ${pkgUPPER}_PATH=${${pkgUPPER}_PATH}, ${_PAR_NAME}_PATH=${${_PAR_NAME}_PATH}, ${_PAR_NAME}_DIR=${${_PAR_NAME}_DIR}")
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} NO_MODULE ${_find_quiet}
+ COMPONENTS ${_PAR_COMPONENTS}
+ HINTS ${${pkgUPPER}_PATH} ${${_PAR_NAME}_PATH} ${${_PAR_NAME}_DIR}
+ NO_DEFAULT_PATH )
+ endif()
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE HINTS ENV ${PNAME}_PATH
- ${NO_DEV_BUILD_DIRS}
- NO_CMAKE_ENVIRONMENT_PATH
- NO_SYSTEM_ENVIRONMENT_PATH
- NO_CMAKE_SYSTEM_PATH
- NO_CMAKE_SYSTEM_PACKAGE_REGISTRY )
+ # 2) search using a file Find<package>.cmake if it exists ( macro should itself take *_PATH into account )
- endif()
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 2) search using a file Find${_PAR_NAME}.cmake if it exists")
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} MODULE ${_find_quiet}
+ COMPONENTS ${_PAR_COMPONENTS} )
+ endif()
- # 4) search special ECMWF paths
+ # is <package>_PATH was given and we don't find anything then we FAIL
- if( NOT ${_PAR_NAME}_FOUND )
+ if( NOT ${_PAR_NAME}_FOUND )
+ if( ${_PAR_NAME}_PATH )
+ message( FATAL_ERROR "${_PAR_NAME}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
+ endif()
+ if( ${pkgUPPER}_PATH )
+ message( FATAL_ERROR "${pkgUPPER}_PATH was provided by user but package ${_PAR_NAME} wasn't found" )
+ endif()
+ endif()
- set( _ecmwf_paths ) # clear variable
- ecbuild_list_extra_search_paths( ${_PAR_NAME} _ecmwf_paths )
+ endif()
- if( _ecmwf_paths )
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE PATHS ${_ecmwf_paths} NO_DEFAULT_PATH )
- endif()
+ # 3) search developer cache and recently configured packages in the CMake GUI if in DEVELOPER_MODE
+ # otherwise only search CMAKE_PREFIX_PATH and <package>_PATH
- endif()
+ if( NOT ${_PAR_NAME}_FOUND )
+ if (NO_DEV_BUILD_DIRS)
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 3) search CMAKE_PREFIX_PATH and \$${pkgUPPER}_PATH")
+ else()
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 3) search CMAKE_PREFIX_PATH and \$${pkgUPPER}_PATH and package registry")
+ endif()
- # 5) search system paths, for <package>-config.cmake
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} NO_MODULE
+ COMPONENTS ${_PAR_COMPONENTS}
+ HINTS ENV ${pkgUPPER}_PATH
+ ${NO_DEV_BUILD_DIRS}
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH
+ NO_CMAKE_SYSTEM_PACKAGE_REGISTRY )
- if( NOT ${_PAR_NAME}_FOUND )
+ endif()
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET NO_MODULE ${NO_DEV_BUILD_DIRS} )
+ # 4) search system paths, for <package>-config.cmake
- endif()
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 5) search system paths, for ${_PAR_NAME}-config.cmake")
- # 6) search system paths, using Find<package>.cmake if it exists
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} NO_MODULE
+ COMPONENTS ${_PAR_COMPONENTS}
+ ${NO_DEV_BUILD_DIRS} )
- if( NOT ${_PAR_NAME}_FOUND )
+ endif()
- find_package( ${_PAR_NAME} ${_${PNAME}_version} QUIET MODULE )
+ # 5) search system paths, using Find<package>.cmake if it exists
- endif()
+ if( NOT ${_PAR_NAME}_FOUND )
+ ecbuild_debug("ecbuild_find_package(${_PAR_NAME}): 6) search system paths, using Find${_PAR_NAME}.cmake if it exists")
- # check version found is acceptable
+ find_package( ${_PAR_NAME} ${_${pkgUPPER}_version} ${_find_quiet} MODULE
+ COMPONENTS ${_PAR_COMPONENTS} )
- if( ${_PAR_NAME}_FOUND )
- set( _version_acceptable 1 )
- if( _PAR_VERSION )
- if( ${_PAR_NAME}_VERSION )
- if( _PAR_EXACT )
- if( NOT ${_PAR_NAME}_VERSION VERSION_EQUAL _PAR_VERSION )
- message( WARNING "${PROJECT_NAME} requires (exactly) ${_PAR_NAME} = ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
- set( _version_acceptable 0 )
- endif()
- else()
- if( _PAR_VERSION VERSION_LESS ${_PAR_NAME}_VERSION OR _PAR_VERSION VERSION_EQUAL ${_PAR_NAME}_VERSION )
- set( _version_acceptable 1 )
- else()
- if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} requires ${_PAR_NAME} >= ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
- endif()
- set( _version_acceptable 0 )
- endif()
- endif()
- else()
- if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but no version information, so cannot check if satisfies ${_PAR_VERSION}" )
- endif()
- set( _version_acceptable 0 )
- endif()
- endif()
- endif()
+ endif()
- if( ${_PAR_NAME}_FOUND )
+ # check version found is acceptable
- if( _version_acceptable )
- set( ${PNAME}_FOUND ${${_PAR_NAME}_FOUND} )
+ if( ${_PAR_NAME}_FOUND )
+ set( _version_acceptable 1 )
+ if( _PAR_VERSION )
+ if( ${_PAR_NAME}_VERSION )
+ if( _PAR_EXACT )
+ if( NOT ${_PAR_NAME}_VERSION VERSION_EQUAL _PAR_VERSION )
+ message( WARNING "${PROJECT_NAME} requires (exactly) ${_PAR_NAME} = ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
+ set( _version_acceptable 0 )
+ endif()
else()
+ if( _PAR_VERSION VERSION_LESS ${_PAR_NAME}_VERSION OR _PAR_VERSION VERSION_EQUAL ${_PAR_NAME}_VERSION )
+ set( _version_acceptable 1 )
+ else()
if( NOT _PAR_QUIET )
- message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but with unsuitable version" )
+ message( WARNING "${PROJECT_NAME} requires ${_PAR_NAME} >= ${_PAR_VERSION} -- found ${${_PAR_NAME}_VERSION}" )
endif()
- set( ${PNAME}_FOUND 0 )
- set( ${_PAR_NAME}_FOUND 0 )
+ set( _version_acceptable 0 )
+ endif()
endif()
-
+ else()
+ if( NOT _PAR_QUIET )
+ message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but no version information, so cannot check if satisfies ${_PAR_VERSION}" )
+ endif()
+ set( _version_acceptable 0 )
+ endif()
+ endif()
+ endif()
+
+ if( ${_PAR_NAME}_FOUND )
+
+ if( _version_acceptable )
+ set( ${pkgUPPER}_FOUND ${${_PAR_NAME}_FOUND} )
+ else()
+ if( NOT _PAR_QUIET )
+ message( WARNING "${PROJECT_NAME} found ${_PAR_NAME} but with unsuitable version" )
+ endif()
+ set( ${pkgUPPER}_FOUND 0 )
+ set( ${_PAR_NAME}_FOUND 0 )
endif()
- ### final messages
-
- if( NOT ${_PAR_NAME}_FOUND )
- if( _PAR_REQUIRED )
- message( FATAL_ERROR
- " ${PROJECT_NAME} FAILED to find REQUIRED package ${_PAR_NAME}"
- " Provide location with \"-D ${PNAME}_DIR=/...\"\n"
- " or export ${PNAME}_DIR in environment"
- )
- else()
- if( NOT _PAR_QUIET )
- message( STATUS
- "${PROJECT_NAME} couldn't find package ${_PAR_NAME}.\n"
- " Provide location with \"-D ${PNAME}_DIR=/...\"\n"
- " or export ${PNAME}_DIR in environment" )
- endif()
- endif()
- endif()
+ endif()
+
+ ### final messages
+
+ set( _failed_message
+ "\n"
+ " ${PROJECT_NAME} FAILED to find package ${_PAR_NAME}\n"
+ "\n"
+ " Provide location with \"-D${pkgUPPER}_PATH=/...\" or \"-D${_PAR_NAME}_DIR=/...\" \n"
+ " You may also export environment variables ${pkgUPPER}_PATH or ${_PAR_NAME}_DIR\n"
+ "\n"
+ " Values (note CAPITALISATION):\n"
+ " ${pkgUPPER}_PATH should contain the path to the install prefix (as in <install>/bin <install>/lib <install>/include)\n"
+ " ${_PAR_NAME}_DIR should be a directory containing a <package>-config.cmake file (usually <install>/share/<package>/cmake)\n"
+ "\n"
+ )
+
+ if( ${_PAR_NAME}_FOUND OR ${pkgUPPER}_FOUND )
+ if( NOT _PAR_QUIET )
+ message( STATUS "[${_PAR_NAME}] (${${_PAR_NAME}_VERSION})" )
+ foreach( var in ITEMS INCLUDE_DIR INCLUDE_DIRS DEFINITIONS LIBRARY LIBRARIES )
+ if( ${pkgUPPER}_${var} )
+ message( STATUS " ${pkgUPPER}_${var} : [${${pkgUPPER}_${var}}]" )
+ elseif( ${_PAR_NAME}_${var} )
+ message( STATUS " ${_PAR_NAME}_${var} : [${${_PAR_NAME}_${var}}]" )
+ endif()
+ endforeach()
+ endif()
+ else()
+ if( _PAR_REQUIRED )
+ message( FATAL_ERROR ${_failed_message} " !! ${PROJECT_NAME} requires package ${_PAR_NAME} !!" )
+ else()
+ if( NOT _PAR_QUIET )
+ message( STATUS ${_failed_message} )
+ endif()
+ endif()
+ endif()
endmacro()
diff --git a/cmake/ecbuild_find_perl.cmake b/cmake/ecbuild_find_perl.cmake
index 2d0cd02..f4c933a 100644
--- a/cmake/ecbuild_find_perl.cmake
+++ b/cmake/ecbuild_find_perl.cmake
@@ -6,40 +6,68 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-# OUTPUT:
+##############################################################################
+#.rst:
+#
+# ecbuild_find_perl
+# =================
+#
+# Find perl executable and its version. ::
+#
+# ecbuild_find_perl( [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# REQUIRED : optional
+# fail if perl was not found
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if perl was found:
+#
+# :PERL_FOUND: perl was found
+# :PERL_EXECUTABLE: path to the perl executable
+# :PERL_VERSION: perl version
+# :PERL_VERSION_STRING: perl version (same as ``PERL_VERSION``)
+#
+##############################################################################
macro( ecbuild_find_perl )
- # parse parameters
+ # parse parameters
- set( options REQUIRED )
- set( single_value_args )
- set( multi_value_args )
+ set( options REQUIRED )
+ set( single_value_args )
+ set( multi_value_args )
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_find_perl(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_p_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_find_perl(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
- find_package( Perl )
+ find_package( Perl )
- if( NOT PERL_EXECUTABLE AND _p_REQUIRED )
- message( FATAL_ERROR "Failed to find Perl (REQUIRED)" )
- endif()
+ if( NOT PERL_EXECUTABLE AND _p_REQUIRED )
+ message( FATAL_ERROR "Failed to find Perl (REQUIRED)" )
+ endif()
- if( PERL_EXECUTABLE )
+ if( PERL_EXECUTABLE )
- execute_process( COMMAND ${PERL_EXECUTABLE} -V:version OUTPUT_VARIABLE perl_version_output_variable RESULT_VARIABLE perl_version_return )
- if( NOT perl_version_return )
- string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION ${perl_version_output_variable})
- endif()
+ execute_process( COMMAND ${PERL_EXECUTABLE} -V:version OUTPUT_VARIABLE perl_version_output_variable RESULT_VARIABLE perl_version_return )
+ if( NOT perl_version_return )
+ string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION ${perl_version_output_variable})
+ endif()
+
+ # from cmake 2.8.8 onwards
+ if( NOT PERL_VERSION_STRING )
+ set( PERL_VERSION_STRING ${PERL_VERSION} )
+ endif()
- # from cmake 2.8.8 onwards
- if( NOT PERL_VERSION_STRING )
- set( PERL_VERSION_STRING ${PERL_VERSION} )
- endif()
+ ecbuild_debug("ecbuild_find_perl: found perl version ${PERL_VERSION_STRING} as ${PERL_EXECUTABLE}")
- endif()
+ endif()
-endmacro( ecbuild_find_perl )
\ No newline at end of file
+endmacro( ecbuild_find_perl )
diff --git a/cmake/ecbuild_find_python.cmake b/cmake/ecbuild_find_python.cmake
index d207ee8..3209826 100644
--- a/cmake/ecbuild_find_python.cmake
+++ b/cmake/ecbuild_find_python.cmake
@@ -6,15 +6,44 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to find python
+##############################################################################
+#.rst:
+#
+# ecbuild_find_python
+# ===================
+#
+# Find Python interpreter, its version and the Python libraries. ::
+#
+# ecbuild_find_python( [ VERSION <version> ] [ REQUIRED ] )
+#
+# Options
+# -------
+#
+# VERSION : optional
+# minimum required version
+#
+# REQUIRED : optional
+# fail if Python was not found
+#
+# Output variables
+# ----------------
+#
+# The following CMake variables are set if perl was found:
+#
+# :PYTHONINTERP_FOUND: Python interpreter was found
+# :PYTHONLIBS_FOUND: Python libraries were found
+# :PYTHON_FOUND: Python was found (both interpreter and libraries)
+# :PYTHON_VERSION_MAJOR: major version number
+# :PYTHON_VERSION_MINOR: minor version number
+# :PYTHON_VERSION_PATCH: patch version number
+# :PYTHON_VERSION_STRING: Python version
+# :PYTHON_INCLUDE_DIRS: Python include directories
+# :PYTHON_LIBRARIES: Python libraries
+# :PYTHON_SITE_PACKAGES: Python site packages directory
+#
+##############################################################################
-# OUTPUT:
-# PYTHONINTERP_FOUND
-# PYTHONLIBS_FOUND
-# PYTHON_INCLUDE_DIRS
-# PYTHON_LIBRARIES
-# PYTHON_SITE_PACKAGES
+set( __test_python ${CMAKE_CURRENT_LIST_DIR}/pymain.c )
macro( ecbuild_find_python )
@@ -63,8 +92,9 @@ macro( ecbuild_find_python )
endif()
if( PYTHONINTERP_FOUND )
+ ecbuild_debug( "ecbuild_find_python: Found Python interpreter version ${PYTHON_VERSION_STRING} at ${PYTHON_EXECUTABLE}" )
- # find pythonn config
+ # find python config
if( PYTHON_EXECUTABLE AND EXISTS ${PYTHON_EXECUTABLE}-config )
set(PYTHON_CONFIG ${PYTHON_EXECUTABLE}-config CACHE PATH "" FORCE)
@@ -78,6 +108,7 @@ macro( ecbuild_find_python )
# that don't reliably report linking flags that will work.
if( PYTHON_CONFIG AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" )
+ ecbuild_debug( "ecbuild_find_python: Searching for Python include directories and libraries using ${PYTHON_CONFIG}" )
execute_process(COMMAND "${PYTHON_CONFIG}" --ldflags
OUTPUT_VARIABLE PYTHON_LIBRARIES
@@ -89,15 +120,13 @@ macro( ecbuild_find_python )
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
-# debug_var(PYTHON_LIBRARIES)
-# debug_var(PYTHON_INCLUDE_DIR)
-
string(REGEX REPLACE "^[-I]" "" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
string(REGEX REPLACE "[ ]-I" " " PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}")
separate_arguments(PYTHON_INCLUDE_DIR)
else() # revert to finding pythonlibs the standard way (cmake macro)
+ ecbuild_debug( "ecbuild_find_python: Searching for Python include directories and libraries using find_package(PythonLibs)" )
find_package(PythonLibs)
if( PYTHON_INCLUDE_PATH AND NOT PYTHON_INCLUDE_DIR )
@@ -106,18 +135,35 @@ macro( ecbuild_find_python )
endif()
+ # Remove duplicate include directories
+ list(REMOVE_DUPLICATES PYTHON_INCLUDE_DIR)
+
+ # Test if we can link against the Python libraries and include Python.h
+ try_compile( PYTHON_LIBS_WORKING ${CMAKE_CURRENT_BINARY_DIR}
+ ${__test_python}
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PYTHON_INCLUDE_DIR}"
+ LINK_LIBRARIES ${PYTHON_LIBRARIES} )
+
# set output variables
- find_package_handle_standard_args( PythonLibs DEFAULT_MSG PYTHON_INCLUDE_DIR PYTHON_LIBRARIES )
+ find_package_handle_standard_args( PythonLibs DEFAULT_MSG
+ PYTHON_INCLUDE_DIR PYTHON_LIBRARIES PYTHON_LIBS_WORKING )
+ ecbuild_debug( "ecbuild_find_python: PYTHON_INCLUDE_DIR=${PYTHON_INCLUDE_DIR}" )
+ ecbuild_debug( "ecbuild_find_python: PYTHON_LIBRARIES=${PYTHON_LIBRARIES}" )
set( PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR} )
set( PYTHON_INCLUDE_PATH ${PYTHON_INCLUDE_DIR} )
- list( REMOVE_DUPLICATES PYTHON_INCLUDE_DIRS )
+ # Also set PYTHON_FOUND and Python_FOUND for compatibility with ecbuild_add_option
+ if( PYTHONLIBS_FOUND )
+ set( PYTHON_FOUND 1 )
+ set( Python_FOUND 1 )
+ endif()
# find where python site-packages are ...
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
+ ecbuild_debug( "ecbuild_find_python: PYTHON_SITE_PACKAGES=${PYTHON_SITE_PACKAGES}" )
endif()
diff --git a/cmake/ecbuild_generate_config_headers.cmake b/cmake/ecbuild_generate_config_headers.cmake
index abf9aac..53be8f3 100644
--- a/cmake/ecbuild_generate_config_headers.cmake
+++ b/cmake/ecbuild_generate_config_headers.cmake
@@ -6,42 +6,58 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# generates the config header fot the project with the system introspection done by CMake
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_config_headers
+# ===============================
+#
+# Generates the ecBuild configuration header for the project with the system
+# introspection done by CMake. ::
+#
+# ecbuild_generate_config_headers( [ DESTINATION <directory> ] )
+#
+# Options
+# -------
+#
+# DESTINATION : optional
+# installation destination directory
+#
+##############################################################################
function( ecbuild_generate_config_headers )
- # parse parameters
+ # parse parameters
- set( options )
- set( single_value_args DESTINATION )
- set( multi_value_args )
+ set( options )
+ set( single_value_args DESTINATION )
+ set( multi_value_args )
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_config_headers(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_config_headers(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- # generate list of compiler flags
+ # generate list of compiler flags
- string( TOUPPER ${PROJECT_NAME} PNAME )
+ string( TOUPPER ${PROJECT_NAME} PNAME )
- get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
+ get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
- foreach( lang ${langs} )
- set( EC_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
- endforeach()
+ foreach( lang ${langs} )
+ set( EC_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
+ endforeach()
- configure_file( ${ECBUILD_MACROS_DIR}/ecbuild_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h )
+ configure_file( ${ECBUILD_MACROS_DIR}/ecbuild_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h )
- # install ecbuild configuration
+ # install ecbuild configuration
- set( _destination ${INSTALL_INCLUDE_DIR} )
- if( _p_DESTINATION )
- set( _destination ${_p_DESTINATION} )
- endif()
+ set( _destination ${INSTALL_INCLUDE_DIR} )
+ if( _p_DESTINATION )
+ set( _destination ${_p_DESTINATION} )
+ endif()
- install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h DESTINATION ${_destination} )
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_ecbuild_config.h DESTINATION ${_destination} )
endfunction( ecbuild_generate_config_headers )
diff --git a/cmake/ecbuild_generate_rpc.cmake b/cmake/ecbuild_generate_rpc.cmake
index 5bd4f76..19fd3eb 100644
--- a/cmake/ecbuild_generate_rpc.cmake
+++ b/cmake/ecbuild_generate_rpc.cmake
@@ -6,8 +6,35 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to process rpcgen files
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_rpc
+# ====================
+#
+# Process RPC (Remote Procedure Call) Language files using rpcgen. ::
+#
+# ecbuild_generate_rpc( SOURCE <file>
+# [ TARGET_H <file> ]
+# [ TARGET_C <file> ]
+# [ DEPENDANT <file1> [ <file2> ... ] ] )
+#
+# Options
+# -------
+#
+# SOURCE : required
+# RPC source file
+#
+# TARGET_H : optional (required if TARGET_C not given)
+# name of header file to be generated
+#
+# TARGET_C : optional (required if TARGET_H not given)
+# name of source file to be generated
+#
+# DEPENDANT : optional
+# list of files which depend on the generated source and header files
+#
+##############################################################################
macro( ecbuild_generate_rpc )
diff --git a/cmake/ecbuild_generate_yy.cmake b/cmake/ecbuild_generate_yy.cmake
index 391bed1..e686434 100644
--- a/cmake/ecbuild_generate_yy.cmake
+++ b/cmake/ecbuild_generate_yy.cmake
@@ -6,108 +6,188 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# macro to process lex/yacc files
+##############################################################################
+#.rst:
+#
+# ecbuild_generate_yy
+# ===================
+#
+# Process lex/yacc files. ::
+#
+# ecbuild_generate_yy( YYPREFIX <prefix>
+# YACC <file>
+# LEX <file>
+# DEPENDANT <file1> [ <file2> ... ]
+# [ SOURCE_DIR <dir> ]
+# [ YACC_TARGET <file> ]
+# [ LEX_TARGET <file> ]
+# [ YACC_FLAGS <flags> ]
+# [ LEX_FLAGS <flags> ]
+# [ BISON_FLAGS <flags> ]
+# [ FLEX_FLAGS <flags> ] )
+#
+# Options
+# -------
+#
+# YYPREFIX : required
+# prefix to use for file and function names
+#
+# YACC : required
+# base name of the yacc source file (without .y extension)
+#
+# LEX : required
+# base name of the lex source file (without .l extension)
+#
+# DEPENDANT : required
+# list of files which depend on the generated lex and yacc target files
+# At least one should be an existing source file (not generated itself).
+#
+# SOURCE_DIR : optional, defaults to CMAKE_CURRENT_SOURCE_DIR
+# directory where yacc and lex source files are located
+#
+# YACC_TARGET : optional, defaults to YACC
+# base name of the generated yacc target file (without .c extension)
+#
+# LEX_TARGET : optional, defaults to LEX
+# base name of the generated lex target file (without .c extension)
+#
+# YACC_FLAGS : optional, defaults to -t
+# flags to pass to yacc executable
+#
+# LEX_FLAGS : optional
+# flags to pass to lex executable
+#
+# BISON_FLAGS : optional, defaults to -t
+# flags to pass to bison executable
+#
+# FLEX_FLAGS : optional, defaults to -l
+# flags to pass to flex executable
+#
+##############################################################################
macro( ecbuild_generate_yy )
- ecbuild_find_lexyacc() # find [ yacc|byson ] and [ lex|flex ]
+ ecbuild_find_lexyacc() # find [ yacc|byson ] and [ lex|flex ]
- ecbuild_find_perl( REQUIRED )
+ ecbuild_find_perl( REQUIRED )
- set( options )
- set( single_value_args YYPREFIX YACC LEX LEX_FLAGS YACC_FLAGS FLEX_FLAGS BISON_FLAGS )
- set( multi_value_args DEPENDANT )
+ set( options )
+ set( single_value_args YYPREFIX YACC LEX SOURCE_DIR YACC_TARGET LEX_TARGET LEX_FLAGS YACC_FLAGS FLEX_FLAGS BISON_FLAGS )
+ set( multi_value_args DEPENDANT )
- cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_PAR_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_yy(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_generate_yy(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
- if( NOT _PAR_YYPREFIX )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YYPREFIX.")
- endif()
+ if( NOT _PAR_YYPREFIX )
+ message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YYPREFIX.")
+ endif()
- if( NOT _PAR_YACC )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YACC file.")
- endif()
+ if( NOT _PAR_YACC )
+ message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the YACC file.")
+ endif()
- if( NOT _PAR_LEX )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the LEX file.")
- endif()
+ if( NOT _PAR_LEX )
+ message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the LEX file.")
+ endif()
- if( NOT _PAR_DEPENDANT )
- message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the DEPENDANT files.")
- endif()
+ if( NOT _PAR_DEPENDANT )
+ message(FATAL_ERROR "The call to ecbuild_generate_yy() doesn't specify the DEPENDANT files.")
+ endif()
- set( BASE ${_PAR_YYPREFIX}_${_PAR_YACC} )
+ set( BASE ${_PAR_YYPREFIX}_${_PAR_YACC} )
- ## default flags
+ ## default flags
- if( NOT _PAR_LEX_FLAGS )
- set( _PAR_LEX_FLAGS "" )
- endif()
+ if( NOT _PAR_LEX_FLAGS )
+ set( _PAR_LEX_FLAGS "" )
+ endif()
- if( NOT _PAR_FLEX_FLAGS )
- set( _PAR_FLEX_FLAGS "-l" )
- endif()
+ if( NOT _PAR_FLEX_FLAGS )
+ set( _PAR_FLEX_FLAGS "-l" )
+ endif()
- if( NOT _PAR_YACC_FLAGS )
- set( _PAR_YACC_FLAGS "-t" )
- endif()
+ if( NOT _PAR_YACC_FLAGS )
+ set( _PAR_YACC_FLAGS "-t" )
+ endif()
- if( NOT _PAR_BISON_FLAGS )
- set( _PAR_BISON_FLAGS "-t" )
- endif()
+ if( NOT _PAR_BISON_FLAGS )
+ set( _PAR_BISON_FLAGS "-t" )
+ endif()
-# debug_var( BASE )
+ if( NOT _PAR_YACC_TARGET )
+ set ( _PAR_YACC_TARGET ${_PAR_YACC} )
+ endif()
- set( ${BASE}yy_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC}.tmp.c )
- set( ${BASE}yl_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX}.tmp.c )
+ if ( NOT _PAR_LEX_TARGET )
+ set ( _PAR_LEX_TARGET ${_PAR_LEX} )
+ endif()
- set( ${BASE}yy_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC}.c )
- set( ${BASE}yl_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX}.c )
+ set( ${BASE}yy_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC_TARGET}.tmp.c )
+ set( ${BASE}yh_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC_TARGET}.tmp.h )
+ set( ${BASE}yl_tmp_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX_TARGET}.tmp.c )
- add_custom_target( ${_PAR_YYPREFIX}_${DEPENDANT} SOURCES ${_PAR_YACC}.y ${_PAR_LEX}.l )
+ set( ${BASE}yy_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC_TARGET}.c )
+ set( ${BASE}yh_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_YACC_TARGET}.h )
+ set( ${BASE}yl_target ${CMAKE_CURRENT_BINARY_DIR}/${_PAR_LEX_TARGET}.c )
- if( BISON_FOUND )
- bison_target( ${BASE}_parser ${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_BISON_FLAGS}" )
- else()
- yacc_target( ${BASE}_parser ${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_YACC_FLAGS}" )
- endif()
+ if( NOT _PAR_SOURCE_DIR )
+ set( _PAR_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
+ endif()
- if( FLEX_FOUND )
- flex_target( ${BASE}_scanner ${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_FLEX_FLAGS}" )
- add_flex_bison_dependency(${BASE}_scanner ${BASE}_parser)
- else()
- lex_target( ${BASE}_scanner ${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_LEX_FLAGS}" )
- add_lex_yacc_dependency(${BASE}_scanner ${BASE}_parser)
- endif()
+ add_custom_target( ${_PAR_YYPREFIX}_${DEPENDANT} SOURCES ${_PAR_SOURCE_DIR}/${_PAR_YACC}.y ${_PAR_SOURCE_DIR}/${_PAR_LEX}.l )
+
+ if( BISON_FOUND )
+ bison_target( ${BASE}_parser ${_PAR_SOURCE_DIR}/${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_BISON_FLAGS}" )
+ else()
+ yacc_target( ${BASE}_parser ${_PAR_SOURCE_DIR}/${_PAR_YACC}.y ${${BASE}yy_tmp_target} COMPILE_FLAGS "${_PAR_YACC_FLAGS}" )
+ endif()
+
+ if( FLEX_FOUND )
+ flex_target( ${BASE}_scanner ${_PAR_SOURCE_DIR}/${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_FLEX_FLAGS}" )
+ add_flex_bison_dependency(${BASE}_scanner ${BASE}_parser)
+ else()
+ lex_target( ${BASE}_scanner ${_PAR_SOURCE_DIR}/${_PAR_LEX}.l ${${BASE}yl_tmp_target} COMPILE_FLAGS "${_PAR_LEX_FLAGS}" )
+ add_lex_yacc_dependency(${BASE}_scanner ${BASE}_parser)
+ endif()
- set_source_files_properties(${${BASE}yy_tmp_target} GENERATED)
- set_source_files_properties(${${BASE}yl_tmp_target} GENERATED)
+ set_source_files_properties(${${BASE}yy_tmp_target} GENERATED)
+ set_source_files_properties(${${BASE}yh_tmp_target} GENERATED)
+ set_source_files_properties(${${BASE}yl_tmp_target} GENERATED)
- add_custom_command(OUTPUT ${${BASE}yy_target}
- COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yy_tmp_target} ${${BASE}yy_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yy_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yy_target}
- DEPENDS ${${BASE}yy_tmp_target}
+ add_custom_command(OUTPUT ${${BASE}yy_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yy_tmp_target} ${${BASE}yy_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yy_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yy_target}
+ DEPENDS ${${BASE}yy_tmp_target}
)
- add_custom_command(OUTPUT ${${BASE}yl_target}
- COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yl_tmp_target} ${${BASE}yl_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yl_target}
- COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yl_target}
- DEPENDS ${${BASE}yl_tmp_target}
+ add_custom_command(OUTPUT ${${BASE}yh_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yh_tmp_target} ${${BASE}yh_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yh_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.h/\\.h/g' ${${BASE}yh_target}
+ DEPENDS ${${BASE}yh_tmp_target}
)
- set_source_files_properties(${${BASE}yy_target} GENERATED)
- set_source_files_properties(${${BASE}yl_target} GENERATED)
+ add_custom_command(OUTPUT ${${BASE}yl_target}
+ COMMAND ${CMAKE_COMMAND} -E copy ${${BASE}yl_tmp_target} ${${BASE}yl_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/yy/${_PAR_YYPREFIX}/g' ${${BASE}yl_target}
+ COMMAND ${PERL_EXECUTABLE} -pi -e 's/\\.tmp\\.c/\\.c/g' ${${BASE}yl_target}
+ DEPENDS ${${BASE}yl_tmp_target}
+ )
+
+ set_source_files_properties(${${BASE}yy_target} GENERATED)
+ set_source_files_properties(${${BASE}yh_target} GENERATED)
+ set_source_files_properties(${${BASE}yl_target} GENERATED)
- foreach( file ${_PAR_DEPENDANT} )
- set_source_files_properties( ${file} PROPERTIES
- OBJECT_DEPENDS "${${BASE}yy_target};${${BASE}yl_target}" )
- endforeach()
+ foreach( file ${_PAR_DEPENDANT} )
+ if( NOT IS_ABSOLUTE ${file})
+ set( file ${_PAR_SOURCE_DIR}/${file} )
+ endif()
+ set_source_files_properties( ${file} PROPERTIES
+ OBJECT_DEPENDS "${${BASE}yy_target};${${BASE}yh_target};${${BASE}yl_target}" )
+ endforeach()
endmacro( ecbuild_generate_yy )
diff --git a/cmake/ecbuild_get_cxx11_flags.cmake b/cmake/ecbuild_get_cxx11_flags.cmake
new file mode 100644
index 0000000..5bfed07
--- /dev/null
+++ b/cmake/ecbuild_get_cxx11_flags.cmake
@@ -0,0 +1,71 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# ecbuild_get_cxx11_flags
+# =======================
+#
+# Set the CMake variable ``${CXX11_FLAGS}`` to the C++11 flags for the current
+# compiler (based on macros from https://github.com/UCL/GreatCMakeCookOff). ::
+#
+# ecbuild_get_cxx11_flags( CXX11_FLAGS )
+#
+##############################################################################
+
+function( ecbuild_get_cxx11_flags CXX11_FLAGS )
+
+ include(CheckCXXCompilerFlag)
+
+ # On older cmake versions + newer compilers,
+ # the given version of CheckCXXCompilerFlags does not quite work.
+ if(CMAKE_VERSION VERSION_LESS 2.8.9)
+ macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+ set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+ CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT}
+ # Some compilers do not fail with a bad flag
+ FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
+ FAIL_REGEX "unrecognized .*option" # GNU
+ FAIL_REGEX "unknown .*option" # Clang
+ FAIL_REGEX "ignoring unknown option" # MSVC
+ FAIL_REGEX "warning D9002" # MSVC, any lang
+ FAIL_REGEX "option.*not supported" # Intel
+ FAIL_REGEX "invalid argument .*option" # Intel
+ FAIL_REGEX "ignoring option .*argument required" # Intel
+ FAIL_REGEX "[Uu]nknown option" # HP
+ FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
+ FAIL_REGEX "command option .* is not recognized" # XL
+ FAIL_REGEX "not supported in this configuration; ignored" # AIX
+ FAIL_REGEX "File with unknown suffix passed to linker" # PGI
+ FAIL_REGEX "WARNING: unknown flag:" # Open64
+ )
+ set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ endmacro ()
+ endif(CMAKE_VERSION VERSION_LESS 2.8.9)
+
+ check_cxx_compiler_flag(-std=c++11 has_std_cpp11)
+ check_cxx_compiler_flag(-std=c++0x has_std_cpp0x)
+ if(MINGW)
+ check_cxx_compiler_flag(-std=gnu++11 has_std_gnupp11)
+ check_cxx_compiler_flag(-std=gnu++0x has_std_gnupp0x)
+ endif(MINGW)
+ if(has_std_gnupp11)
+ set(${CXX11_FLAGS} "-std=gnu++11" PARENT_SCOPE)
+ elseif(has_std_gnupp0x)
+ set(${CXX11_FLAGS} "-std=gnu++0x" PARENT_SCOPE)
+ elseif(has_std_cpp11)
+ set(${CXX11_FLAGS} "-std=c++11" PARENT_SCOPE)
+ elseif(has_std_cpp0x)
+ set(${CXX11_FLAGS} "-std=c++0x" PARENT_SCOPE)
+ else()
+ message(FATAL ERROR "Could not detect C++11 flags")
+ endif(has_std_gnupp11)
+
+endfunction()
diff --git a/cmake/ecbuild_get_date.cmake b/cmake/ecbuild_get_date.cmake
index afe3d09..8c24623 100644
--- a/cmake/ecbuild_get_date.cmake
+++ b/cmake/ecbuild_get_date.cmake
@@ -6,8 +6,18 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# get date macro
+##############################################################################
+#.rst:
+#
+# ecbuild_get_date
+# ================
+#
+# Set the CMake variable ``${DATE}`` to the current date in the form
+# YYYY.mm.DD. ::
+#
+# ecbuild_get_date( DATE )
+#
+##############################################################################
macro(ecbuild_get_date RESULT)
if(UNIX)
@@ -18,8 +28,18 @@ macro(ecbuild_get_date RESULT)
endif()
endmacro(ecbuild_get_date)
-############################################################################################
-# get timestamp
+##############################################################################
+#.rst:
+#
+# ecbuild_get_timestamp
+# =====================
+#
+# Set the CMake variable ``${TIMESTAMP}`` to the current date and time in the
+# form YYYYmmDDHHMMSS. ::
+#
+# ecbuild_get_timestamp( TIMESTAMP )
+#
+##############################################################################
macro(ecbuild_get_timestamp RESULT)
if(UNIX)
diff --git a/cmake/ecbuild_get_test_data.cmake b/cmake/ecbuild_get_test_data.cmake
index b617a7d..ee585ca 100644
--- a/cmake/ecbuild_get_test_data.cmake
+++ b/cmake/ecbuild_get_test_data.cmake
@@ -1,76 +1,129 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
##############################################################################
+
# function for downloading test data
function( _download_test_data _p_NAME _p_DIRNAME )
- # TODO: make that 'at ecmwf'
- #if(1)
- #unset(ENV{no_proxy})
- #unset(ENV{NO_PROXY})
- #set(ENV{http_proxy} "http://proxy.ecmwf.int:3333")
- #endif()
+ # TODO: make that 'at ecmwf'
+ #if(1)
+ #unset(ENV{no_proxy})
+ #unset(ENV{NO_PROXY})
+ #set(ENV{http_proxy} "http://proxy.ecmwf.int:3333")
+ #endif()
- find_program( CURL_PROGRAM curl )
+ find_program( CURL_PROGRAM curl )
- if( CURL_PROGRAM )
+ if( CURL_PROGRAM )
- add_custom_command( OUTPUT ${_p_NAME}
- COMMENT "(curl) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
- COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_NAME} http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
-
- else()
+ add_custom_command( OUTPUT ${_p_NAME}
+ COMMENT "(curl) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
+ COMMAND ${CURL_PROGRAM} --silent --show-error --fail --output ${_p_NAME}
+ http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
- find_program( WGET_PROGRAM wget )
+ else()
- if( WGET_PROGRAM )
+ find_program( WGET_PROGRAM wget )
- add_custom_command( OUTPUT ${_p_NAME}
- COMMENT "(wget) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
- COMMAND ${WGET_PROGRAM} -nv -O ${_p_NAME} http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
+ if( WGET_PROGRAM )
- else()
+ add_custom_command( OUTPUT ${_p_NAME}
+ COMMENT "(wget) downloading http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME}"
+ COMMAND ${WGET_PROGRAM} -nv -O ${_p_NAME}
+ http://download.ecmwf.org/test-data/${_p_DIRNAME}/${_p_NAME} )
- if( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
- message( WARNING "Couldn't find curl neither wget -- cannot download test data from server.\nPlease obtain the test data by other means and pleace it in the build directory." )
- set( WARNING_CANNOT_DOWNLOAD_TEST_DATA 1 CACHE INTERNAL "Couldn't find curl neither wget -- cannot download test data from server" )
- mark_as_advanced( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
- endif()
+ else()
- endif()
+ if( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
+ message( WARNING "Couldn't find curl neither wget -- cannot download test data from server.\nPlease obtain the test data by other means and pleace it in the build directory." )
+ set( WARNING_CANNOT_DOWNLOAD_TEST_DATA 1 CACHE INTERNAL "Couldn't find curl neither wget -- cannot download test data from server" )
+ mark_as_advanced( WARNING_CANNOT_DOWNLOAD_TEST_DATA )
+ endif()
endif()
-endfunction()
+ endif()
+endfunction()
##############################################################################
-# function for getting test data
+#.rst:
+#
+# ecbuild_get_test_data
+# =====================
+#
+# Download a test data set at build time. ::
+#
+# ecbuild_get_test_data( NAME <name>
+# [ TARGET <target> ]
+# [ DIRNAME <dir> ]
+# [ MD5 <hash> ]
+# [ EXTRACT ]
+# [ NOCHECK ] )
+#
+# curl or wget is required (curl is preferred if available).
+#
+# Options
+# -------
+#
+# NAME : required
+# name of the test data file
#
-# examples:
+# TARGET : optional, defaults to test_data_<name>
+# CMake target name
#
-## no check done
-# ecbuild_get_test_data( NAME msl.grib NOCHECK )
+# DIRNAME : optional, defaults to <project>/<relative path to current dir>
+# directory in which the test data resides
#
-## checksum agains remote md5 file
-# ecbuild_get_test_data( NAME msl.grib )
+# MD5 : optional, ignored if NOCHECK is given
+# md5 checksum of the data set to verify. If not given and NOCHECK is *not*
+# set, download the md5 checksum and verify
#
-## checksum agains local md5
-# ecbuild_get_test_data( NAME msl.grib MD5 f69ca0929d1122c7878d19f32401abe9 )
+# EXTRACT : optional
+# extract the downloaded file (supported archives: tar, zip, tar.gz, tar.bz2)
#
-## (DEPRECATED) checksum agains local sha1
-# ecbuild_get_test_data( NAME msl.grib SHA1 5a8e8c57c510b64e31863ca47cfc3b65971089d9 )
+# NOCHECK : optional
+# do not verify the md5 checksum of the data file
+#
+# Usage
+# -----
+#
+# Download test data from ``http://download.ecmwf.org/test-data/<DIRNAME>/<NAME>``
+#
+# If the ``DIRNAME`` argument is not given, the project name followed by the
+# relative path from the root directory to the current directory is used.
+#
+# By default, the downloaded file is verified against an md5 checksum, either
+# given as the ``MD5`` argument or downloaded from the server otherwise. Use
+# the argument ``NOCHECK`` to disable this check.
+#
+# Examples
+# --------
+#
+# Do not verify the checksum: ::
+#
+# ecbuild_get_test_data( NAME msl.grib NOCHECK )
+#
+# Checksum agains remote md5 file: ::
+#
+# ecbuild_get_test_data( NAME msl.grib )
+#
+# Checksum agains local md5: ::
+#
+# ecbuild_get_test_data( NAME msl.grib MD5 f69ca0929d1122c7878d19f32401abe9 )
+#
+##############################################################################
function( ecbuild_get_test_data )
- set( options NOCHECK )
+ set( options NOCHECK EXTRACT )
set( single_value_args TARGET URL NAME DIRNAME MD5 SHA1)
set( multi_value_args )
@@ -80,7 +133,7 @@ function( ecbuild_get_test_data )
message(FATAL_ERROR "Unknown keywords given to ecbuild_get_test_data(): \"${_p_UNPARSED_ARGUMENTS}\"")
endif()
- file( RELATIVE_PATH currdir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
+ file( RELATIVE_PATH currdir ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} )
### check parameters
@@ -113,38 +166,38 @@ function( ecbuild_get_test_data )
if( NOT _p_NOCHECK )
- find_program( MD5SUM md5sum )
-
- if( MD5SUM AND NOT _p_MD5 AND NOT _p_SHA1) # use remote md5
+ if( NOT _p_MD5 AND NOT _p_SHA1) # use remote md5
# message( STATUS " --- getting MD5 sum " )
add_custom_command( OUTPUT ${_p_NAME}.localmd5
- COMMAND ${MD5SUM} -t ${_p_NAME} > ${_p_NAME}.localmd5
+ COMMAND ${CMAKE_COMMAND} -E md5sum ${_p_NAME} > ${_p_NAME}.localmd5
DEPENDS ${_p_NAME} )
_download_test_data( ${_p_NAME}.md5 ${_p_DIRNAME} )
- add_custom_command( OUTPUT ${_p_NAME}.ok
- COMMAND diff ${_p_NAME}.md5 ${_p_NAME}.localmd5 && touch ${_p_NAME}.ok
+ add_custom_command( OUTPUT ${_p_NAME}.ok
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${_p_NAME}.md5 ${_p_NAME}.localmd5 &&
+ ${CMAKE_COMMAND} -E touch ${_p_NAME}.ok
DEPENDS ${_p_NAME}.localmd5 ${_p_NAME}.md5 )
list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
endif()
- if( MD5SUM AND _p_MD5 )
+ if( _p_MD5 )
# message( STATUS " --- computing MD5 sum [${_p_MD5}]" )
add_custom_command( OUTPUT ${_p_NAME}.localmd5
- COMMAND ${MD5SUM} -t ${_p_NAME} > ${_p_NAME}.localmd5
+ COMMAND ${CMAKE_COMMAND} -E md5sum ${_p_NAME} > ${_p_NAME}.localmd5
DEPENDS ${_p_NAME} )
configure_file( "${ECBUILD_MACROS_DIR}/md5.in" ${_p_NAME}.md5 @ONLY )
add_custom_command( OUTPUT ${_p_NAME}.ok
- COMMAND diff ${_p_NAME}.md5 ${_p_NAME}.localmd5 && touch ${_p_NAME}.ok
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${_p_NAME}.md5 ${_p_NAME}.localmd5 &&
+ ${CMAKE_COMMAND} -E touch ${_p_NAME}.ok
DEPENDS ${_p_NAME}.localmd5 )
list( APPEND _deps ${_p_NAME}.localmd5 ${_p_NAME}.ok )
@@ -174,23 +227,86 @@ function( ecbuild_get_test_data )
add_custom_target( ${_p_TARGET} DEPENDS ${_deps} )
+ if( _p_EXTRACT )
+ ecbuild_debug("ecbuild_get_test_data: extracting ${_p_NAME} (post-build for target ${_p_TARGET}")
+ add_custom_command( TARGET ${_p_TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E tar xv ${_p_NAME} )
+ endif()
+
endfunction(ecbuild_get_test_data)
##############################################################################
-# function for getting test data
+#.rst:
+#
+# ecbuild_get_test_multidata
+# ==========================
+#
+# Download multiple test data sets at build time. ::
+#
+# ecbuild_get_test_multidata( NAMES <name1> [ <name2> ... ]
+# TARGET <target>
+# [ DIRNAME <dir> ]
+# [ EXTRACT ]
+# [ NOCHECK ] )
+#
+# curl or wget is required (curl is preferred if available).
+#
+# Options
+# -------
+#
+# NAMES : required
+# list of names of the test data files
+#
+# TARGET : optional
+# CMake target name
+#
+# DIRNAME : optional, defaults to <project>/<relative path to current dir>
+# directory in which the test data resides
+#
+# EXTRACT : optional
+# extract downloaded files (supported archives: tar, zip, tar.gz, tar.bz2)
+#
+# NOCHECK : optional
+# do not verify the md5 checksum of the data file
#
-# examples:
+# Usage
+# -----
#
-## no check done
-# ecbuild_get_test_multidata( TARGET get_foobar_data NAMES foo.grib bar.grib DIRNAME test/data/dir NOCHECK )
+# Download test data from ``http://download.ecmwf.org/test-data/<DIRNAME>``
+# for each name given in the list of ``NAMES``. Each name may contain a
+# relative path, which is appended to ``DIRNAME`` and may be followed by an
+# md5 checksum, separated with a ``:`` (the name must not contain spaces).
#
-## check for remote md5
-# ecbuild_get_test_multidata( TARGET get_foobar_data NAMES foo.grib bar.grib DIRNAME test/data/dir )
+# If the ``DIRNAME`` argument is not given, the project name followed by the
+# relative path from the root directory to the current directory is used.
#
+# By default, each downloaded file is verified against an md5 checksum, either
+# given as part of the name as described above or a remote checksum downloaded
+# from the server. Use the argument ``NOCHECK`` to disable this check.
+#
+# Examples
+# --------
+#
+# Do not verify checksums: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data NAMES foo.grib bar.grib
+# DIRNAME test/data/dir NOCHECK )
+#
+# Checksums agains remote md5 file: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data NAMES foo.grib bar.grib
+# DIRNAME test/data/dir )
+#
+# Checksum agains local md5: ::
+#
+# ecbuild_get_test_multidata( TARGET get_grib_data DIRNAME test/data/dir
+# NAMES msl.grib:f69ca0929d1122c7878d19f32401abe9 )
+#
+##############################################################################
function( ecbuild_get_test_multidata )
- set( options NOCHECK )
+ set( options EXTRACT NOCHECK )
set( single_value_args TARGET DIRNAME )
set( multi_value_args NAMES )
@@ -214,6 +330,10 @@ function( ecbuild_get_test_multidata )
# debug_var( _p_NAME )
# debug_var( _p_DIRNAME )
+ if( _p_EXTRACT )
+ set( _extract EXTRACT )
+ endif()
+
if( _p_NOCHECK )
set( _nocheck NOCHECK )
endif()
@@ -259,13 +379,19 @@ endfunction()\n\n" )
#debug_var(_name)
#debug_var(_md5)
- ecbuild_get_test_data( TARGET __get_data_${_p_TARGET}_${_name} NAME ${_file} ${_dirname} ${_md5} ${_nocheck} )
+ ecbuild_get_test_data(
+ TARGET __get_data_${_p_TARGET}_${_name}
+ NAME ${_file} ${_dirname} ${_md5} ${_extract} ${_nocheck} )
- file( APPEND ${_script} "exec_check( ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target __get_data_${_p_TARGET}_${_name} )\n" )
+ # The option /fast disables dependency checking on a target, see
+ # https://cmake.org/Wiki/CMake_FAQ#Is_there_a_way_to_skip_checking_of_dependent_libraries_when_compiling.3F
+ file( APPEND ${_script}
+ "exec_check( \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --target __get_data_${_p_TARGET}_${_name}/fast )\n" )
endforeach()
- add_test( NAME ${_p_TARGET} COMMAND ${CMAKE_COMMAND} -P ${_script} )
+ if( ENABLE_TESTS )
+ add_test( NAME ${_p_TARGET} COMMAND ${CMAKE_COMMAND} -P ${_script} )
+ endif()
endfunction(ecbuild_get_test_multidata)
-
diff --git a/cmake/ecbuild_git.cmake b/cmake/ecbuild_git.cmake
new file mode 100644
index 0000000..42124db
--- /dev/null
+++ b/cmake/ecbuild_git.cmake
@@ -0,0 +1,307 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+set( ECBUILD_GIT ON CACHE BOOL "Turn on/off ecbuild_git() function" )
+
+if( ECBUILD_GIT )
+
+ find_package(Git)
+
+ set( ECMWF_USER $ENV{USER} CACHE STRING "ECMWF git user" )
+ set( ECMWF_GIT SSH CACHE STRING "ECMWF git protocol" )
+
+ set( ECMWF_GIT_SSH "ssh://git@software.ecmwf.int:7999" CACHE INTERNAL "ECMWF ssh address" )
+ set( ECMWF_GIT_HTTPS "https://${ECMWF_USER}@software.ecmwf.int/stash/scm" CACHE INTERNAL "ECMWF https address" )
+
+ if( ECMWF_GIT MATCHES "[Ss][Ss][Hh]" )
+ set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_SSH} CACHE INTERNAL "" )
+ else()
+ set( ECMWF_GIT_ADDRESS ${ECMWF_GIT_HTTPS} CACHE INTERNAL "" )
+ endif()
+
+endif()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_git
+# ===========
+#
+# Manages an external Git repository. ::
+#
+# ecbuild_git( PROJECT <name>
+# DIR <directory>
+# URL <giturl>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# DIR : required
+# directory to clone the repository into (can be relative)
+#
+# URL : required
+# Git URL of the remote repository to clone (see ``git help clone``)
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+##############################################################################
+
+macro( ecbuild_git )
+
+ set( options UPDATE NOREMOTE MANUAL )
+ set( single_value_args PROJECT DIR URL TAG BRANCH )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ if( DEFINED _PAR_BRANCH AND DEFINED _PAR_TAG )
+ message( FATAL_ERROR "Cannot defined both BRANCH and TAG in macro ecbuild_git" )
+ endif()
+
+ if( _PAR_UPDATE AND _PAR_NOREMOTE )
+ message( FATAL_ERROR "Cannot pass both NOREMOTE and UPDATE in macro ecbuild_git" )
+ endif()
+
+ if(_PAR_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_git(): \"${_PAR_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if( ECBUILD_GIT )
+
+ set( _needs_switch 0 )
+
+ get_filename_component( ABS_PAR_DIR "${_PAR_DIR}" ABSOLUTE )
+ get_filename_component( PARENT_DIR "${_PAR_DIR}/.." ABSOLUTE )
+
+ ### clone if no directory
+
+ if( NOT EXISTS "${_PAR_DIR}" )
+
+ message( STATUS "Cloning ${_PAR_PROJECT} from ${_PAR_URL} into ${_PAR_DIR}...")
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} "clone" ${_PAR_URL} ${clone_args} ${_PAR_DIR} "-q"
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${PARENT_DIR}")
+ if(nok)
+ message(FATAL_ERROR "${_PAR_DIR} git clone failed: ${error}\n")
+ endif()
+ message( STATUS "${_PAR_DIR} retrieved.")
+ set( _needs_switch 1 )
+
+ endif()
+
+ ### check current tag and sha1
+
+ if( IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ OUTPUT_VARIABLE _sha1 RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if(nok)
+ message(STATUS "git rev-parse HEAD on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
+ OUTPUT_VARIABLE _current_branch RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if( nok OR _current_branch STREQUAL "" )
+ message(STATUS "git rev-parse --abbrev-ref HEAD on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ #message(STATUS "git describe --exact-match --abbrev=0 @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND ${GIT_EXECUTABLE} describe --exact-match --abbrev=0
+ OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+
+ if( error MATCHES "no tag exactly matches" OR error MATCHES "No names found" )
+ unset( _current_tag )
+ else()
+ if( nok )
+ message(STATUS "git describe --exact-match --abbrev=0 on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+ endif()
+
+ if( NOT _current_tag ) # try nother method
+ #message(STATUS "git name-rev --tags --name-only @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND ${GIT_EXECUTABLE} name-rev --tags --name-only ${_sha1}
+ OUTPUT_VARIABLE _current_tag RESULT_VARIABLE nok ERROR_VARIABLE error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ WORKING_DIRECTORY "${ABS_PAR_DIR}" )
+ if( nok OR _current_tag STREQUAL "" )
+ message(STATUS "git name-rev --tags --name-only on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+ endif()
+
+ endif()
+
+ if( NOT _PAR_MANUAL AND DEFINED _PAR_BRANCH AND NOT "${_current_branch}" STREQUAL "${_PAR_BRANCH}" )
+ set( _needs_switch 1 )
+ endif()
+
+ if( NOT _PAR_MANUAL AND DEFINED _PAR_TAG AND NOT "${_current_tag}" STREQUAL "${_PAR_TAG}" )
+ set( _needs_switch 1 )
+ endif()
+
+ if( DEFINED _PAR_BRANCH AND _PAR_UPDATE AND NOT _PAR_NOREMOTE )
+
+ add_custom_target( git_update_${_PAR_PROJECT}
+ COMMAND "${GIT_EXECUTABLE}" pull -q
+ WORKING_DIRECTORY "${ABS_PAR_DIR}"
+ COMMENT "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR}" )
+
+ set( git_update_targets "git_update_${_PAR_PROJECT};${git_update_targets}" )
+
+ endif()
+
+ ### updates
+
+ if( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ # debug_here( ABS_PAR_DIR )
+ # debug_here( _sha1 )
+ # debug_here( _current_branch )
+ # debug_here( _current_tag )
+ # debug_here( _PAR_TAG )
+ # debug_here( _PAR_BRANCH )
+ # debug_here( _needs_switch )
+ # debug_here( _PAR_UPDATE )
+
+ if( DEFINED _PAR_BRANCH )
+ set ( _gitref ${_PAR_BRANCH} )
+ message(STATUS "Updating ${_PAR_PROJECT} to head of BRANCH ${_PAR_BRANCH}...")
+ else()
+ message(STATUS "Updating ${_PAR_PROJECT} to TAG ${_PAR_TAG}...")
+ set ( _gitref ${_PAR_TAG} )
+ endif()
+
+ # fetching latest tags and branches
+
+ if( NOT _PAR_NOREMOTE )
+
+ message(STATUS "git fetch --all @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ message(STATUS "git fetch --all in ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ message(STATUS "git fetch --all --tags @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" fetch --all --tags -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ message(STATUS "git fetch --all --tags in ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ else()
+ message(STATUS "${_PAR_DIR} marked NOREMOTE : Skipping git fetch")
+ endif()
+
+ # checking out gitref
+
+ message(STATUS "git checkout ${_gitref} @ ${ABS_PAR_DIR}")
+ execute_process( COMMAND "${GIT_EXECUTABLE}" checkout -q "${_gitref}"
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ message(FATAL_ERROR "git checkout ${_gitref} on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ if( DEFINED _PAR_BRANCH AND _PAR_UPDATE ) #############################################################################
+
+ execute_process( COMMAND "${GIT_EXECUTABLE}" pull -q
+ RESULT_VARIABLE nok ERROR_VARIABLE error
+ WORKING_DIRECTORY "${ABS_PAR_DIR}")
+ if(nok)
+ message(STATUS "git pull of branch ${_PAR_BRANCH} on ${_PAR_DIR} failed:\n ${error}")
+ endif()
+
+ endif() ####################################################################################
+
+ endif( _needs_switch AND IS_DIRECTORY "${_PAR_DIR}/.git" )
+
+ endif( ECBUILD_GIT )
+
+endmacro()
+
+##############################################################################
+#.rst:
+#
+# ecbuild_stash
+# =============
+#
+# Manages an external Git repository on ECMWF Stash. ::
+#
+# ecbuild_stash( PROJECT <name>
+# DIR <directory>
+# STASH <repository>
+# [ BRANCH <gitbranch> | TAG <gittag> ]
+# [ UPDATE | NOREMOTE ] )
+# [ MANUAL ] )
+#
+# Options
+# -------
+#
+# PROJECT : required
+# project name for the Git repository to be managed
+#
+# DIR : required
+# directory to clone the repository into (can be relative)
+#
+# STASH : required
+# Stash repository in the form <project>/<repository>
+#
+# BRANCH : optional, cannot be combined with TAG
+# Git branch to check out
+#
+# TAG : optional, cannot be combined with BRANCH
+# Git tag or commit id to check out
+#
+# UPDATE : optional, requires BRANCH, cannot be combined with NOREMOTE
+# Create a CMake target update to fetch changes from the remote repository
+#
+# NOREMOTE : optional, cannot be combined with UPDATE
+# Do not fetch changes from the remote repository
+#
+# MANUAL : optional
+# Do not automatically switch branches or tags
+#
+##############################################################################
+
+macro( ecmwf_stash )
+
+ set( options )
+ set( single_value_args STASH )
+ set( multi_value_args )
+ cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+
+ ecbuild_git( URL "${ECMWF_GIT_ADDRESS}/${_PAR_STASH}.git" ${_PAR_UNPARSED_ARGUMENTS} )
+
+endmacro()
diff --git a/cmake/ecbuild_install_package.cmake b/cmake/ecbuild_install_project.cmake
similarity index 66%
rename from cmake/ecbuild_install_package.cmake
rename to cmake/ecbuild_install_project.cmake
index dec046f..a7d84a4 100644
--- a/cmake/ecbuild_install_package.cmake
+++ b/cmake/ecbuild_install_project.cmake
@@ -1,15 +1,77 @@
# (C) Copyright 1996-2014 ECMWF.
-#
+#
# This software is licensed under the terms of the Apache Licence Version 2.0
-# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
-# In applying this licence, ECMWF does not waive the privileges and immunities
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-###############################################################################
+##############################################################################
+#.rst:
+#
+# ecbuild_install_project
+# =======================
+#
+# Set up packaging and export configuration. ::
+#
+# ecbuild_install_project( NAME <name> [ DESCRIPTION <description> ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# project name used for packaging
+#
+# DESCRIPTION : optional
+# project description used for packaging
+#
+# Usage
+# -----
+#
+# ``ecbuild_install_project`` should be called at the very end of any ecBuild
+# project (only followed by ``ecbuild_print_summary``), sets up packaging of
+# the project with cpack and exports the configuration and targets for other
+# projects to use.
+#
+# In a top-level project, the following files are generated:
+#
+# :<project>-config.cmake: default project configuration
+# :<project>-config-version.cmake: project version number
+# :<project>-import.cmake: extra project configuration (optional)
+# :<project>-config.cmake.tpls: 3rd party project configurations
+# :<project>-targets.cmake: exported targets
+#
+# For ``<project>-import.cmake`` to be exported to build and install tree,
+# ``<project>-import.cmake`` or ``<project>-import.cmake.in`` must exist in
+# the source tree. ``<project>-config.cmake.in`` and
+# ``<project>-config-version.cmake.in`` can be provided in the source tree to
+# override the default templates used to generate ``<project>-config.cmake``
+# and ``<project>-config-version.cmake``.
+#
+# In DEVELOPER_MODE, the build tree location is also added to the CMake user
+# package registry.
+#
+# If the project is added as a subdirectory, the following CMake variables
+# are set in the parent scope:
+#
+# :<PROJECT>_FOUND: set to ``TRUE``
+# :<project>_FOUND: set to ``TRUE``
+# :<PROJECT>_VERSION: version string
+# :<project>_VERSION: version string
+# :<PROJECT>_INCLUDE_DIRS: list of include directories
+# :<PROJECT>_LIBRARIES: list of libraries
+# :<PROJECT>_DEFINITIONS: list of compiler definitions
+# :<PROJECT>_TPLS: list of 3rd party dependencies
+# :<PROJECT>_TPL_LIBRARIES: libraries of 3rd party dependencies
+# :<PROJECT>_TPL_DEFINITIONS: compiler definitions of 3rd party dependencies
+# :<PROJECT>_TPL_INCLUDE_DIRS: include directories of 3rd party dependencies
+# :<PROJECT>_FEATURES: list of enabled features
+# :<PROJECT>_HAVE_<FEATURE>: set to 1 for each enabled features
+#
+##############################################################################
-macro( ecbuild_install_project )
+macro( ecbuild_install_project )
set( options )
set( single_value_args NAME DESCRIPTION )
@@ -27,9 +89,9 @@ macro( ecbuild_install_project )
### PACKAGING ########################################################
- string( TOUPPER ${PROJECT_NAME} PNAME )
- string( TOLOWER ${PROJECT_NAME} LNAME )
-
+ set( PNAME ${PROJECT_NAME_CAPS} )
+ set( LNAME ${PROJECT_NAME_LOWCASE} )
+
# components
# if( DEFINED _PAR_COMPONENTS )
@@ -37,7 +99,7 @@ macro( ecbuild_install_project )
# else()
# set(CPACK_COMPONENTS_ALL "${PROJECT_NAME}")
# endif()
-
+
# name, version, etc ...
set(CPACK_PACKAGE_NAME "${_PAR_NAME}")
@@ -68,17 +130,17 @@ macro( ecbuild_install_project )
if( EXISTS ${PROJECT_SOURCE_DIR}/INSTALL )
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/INSTALL")
endif()
- if( EXISTS ${PROJECT_SOURCE_DIR}/LICENSE )
+ if( EXISTS ${PROJECT_SOURCE_DIR}/LICENSE )
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
endif()
# set(CPACK_PACKAGE_EXECUTABLES ${ECBUILD_ALL_EXES})
- list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES
- "${PROJECT_SOURCE_DIR}" "."
- "${ECBUILD_MACROS_DIR}" "cmake/" )
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES
+ "${PROJECT_SOURCE_DIR}" "."
+ "${ECBUILD_MACROS_DIR}" "cmake/" )
- # what to pack and not
+ # what to pack and not
set(CPACK_SOURCE_IGNORE_FILES
/build/
@@ -93,6 +155,25 @@ macro( ecbuild_install_project )
list( APPEND CPACK_SOURCE_IGNORE_FILES ${ECBUILD_DONT_PACK_FILES} )
+ # Find the ecbuild toolchain files and include in the source package if found
+ find_path( ECBUILD_TOOLCHAIN_DIR ecmwf-XC30-GNU.cmake
+ PATHS ${ECBUILD_MACROS_DIR}/../toolchains
+ ${ECBUILD_MACROS_DIR}/../share/ecbuild/toolchains )
+
+ if( ECBUILD_TOOLCHAIN_DIR )
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES "${ECBUILD_TOOLCHAIN_DIR}" "share/ecbuild/toolchains/" )
+ endif()
+
+ # Find the ecbuild bin directory and include in the source package if found
+ find_program( ECBUILD_SCRIPT ecbuild
+ PATHS ${ECBUILD_MACROS_DIR}/../bin
+ ${ECBUILD_MACROS_DIR}/../../../bin )
+
+ if( ECBUILD_SCRIPT )
+ get_filename_component( ECBUILD_BIN_DIR ${ECBUILD_SCRIPT} PATH )
+ list( APPEND CPACK_SOURCE_INSTALLED_DIRECTORIES "${ECBUILD_BIN_DIR}" "bin/" )
+ endif()
+
# cpack config file
# set(CPACK_INSTALL_CMAKE_PROJECTS "${${PROJECT_NAME}_BINARY_DIR}" "${PROJECT_NAME}" "${CPACK_COMPONENTS_ALL}" "*" )
@@ -100,7 +181,13 @@ macro( ecbuild_install_project )
include( CPack )
### EXPORTS ########################################################
-
+
+ ecbuild_enabled_features( ${PROJECT_NAME_CAPS}_FEATURES )
+ foreach( _f ${${PNAME}_FEATURES} )
+ set( ${PNAME}_HAVE_${_f} 1 )
+ endforeach()
+
+ message( STATUS "${PROJECT_NAME_CAPS}_TPLS: ${${PROJECT_NAME_CAPS}_TPLS}" )
foreach( _tpl ${${PNAME}_TPLS} )
string( TOUPPER ${_tpl} _TPL )
@@ -136,31 +223,33 @@ macro( ecbuild_install_project )
if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
- # exports the package for use from the build-tree -- inserts <package> into the CMake user package registry
-
- export( PACKAGE ${PROJECT_NAME} )
-
+ # exports the package for use from the build-tree but only in DEVELOPER_MODE
+ # inserts <package> into the CMake user package registry
+
+ if( DEVELOPER_MODE )
+ export( PACKAGE ${PROJECT_NAME} )
+ endif()
+
set( _template_config "${ECBUILD_MACROS_DIR}/project-config.cmake.in" )
if( EXISTS ${LNAME}-config.cmake.in )
set( _template_config "${LNAME}-config.cmake.in" )
endif()
-
+
set( _template_config_version "${ECBUILD_MACROS_DIR}/project-config-version.cmake.in" )
if( EXISTS ${LNAME}-config-version.cmake.in )
set( _template_config_version "${LNAME}-config-version.cmake.in" )
endif()
-
+
# project-config-version.cmake -- format ([0-9]+).([0-9]+).([0-9]+)
-
- set( PACKAGE_VERSION "${${PNAME}_VERSION}" )
-
+
+ set( PACKAGE_VERSION "${${PNAME}_VERSION}" )
+
configure_file( "${_template_config_version}" "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" @ONLY )
install( FILES "${PROJECT_BINARY_DIR}/${LNAME}-config-version.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
# prepare imutable variables (don't depend on install path)
- set( CONF_FEATURES "" )
if( ${PNAME}_FEATURES )
set( CONF_FEATURES ${${PNAME}_FEATURES} )
endif()
@@ -169,7 +258,7 @@ macro( ecbuild_install_project )
if( ${PNAME}_LIBRARIES )
set( CONF_LIBRARIES ${${PNAME}_LIBRARIES} )
endif()
-
+
set( CONF_DEFINITIONS "" )
if( ${PNAME}_DEFINITIONS )
set( CONF_DEFINITIONS ${${PNAME}_DEFINITIONS} )
@@ -205,11 +294,20 @@ macro( ecbuild_install_project )
set( CONF_IMPORT_FILE "${LNAME}-import.cmake" )
+ # If <project>-import.cmake.in exist in source tree, configure it to
+ # the build tree and install the configured version
if( EXISTS "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in" )
- configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in"
- "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" @ONLY )
- install( FILES "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}"
- DESTINATION "${INSTALL_CMAKE_DIR}" )
+ configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}.in"
+ "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" @ONLY )
+ install( FILES "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}"
+ DESTINATION "${INSTALL_CMAKE_DIR}" )
+ # Otherwise, if <project>-import.cmake exist in source tree, copy it to
+ # the build tree and install it
+ elseif( EXISTS "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}" )
+ configure_file( "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}"
+ "${PROJECT_BINARY_DIR}/${CONF_IMPORT_FILE}" COPYONLY )
+ install( FILES "${PROJECT_SOURCE_DIR}/${CONF_IMPORT_FILE}"
+ DESTINATION "${INSTALL_CMAKE_DIR}" )
endif()
set( _lname_config "${PROJECT_BINARY_DIR}/${LNAME}-config.cmake")
@@ -235,7 +333,7 @@ macro( ecbuild_install_project )
endif()
# project-config.cmake @ install tree
-
+
file( RELATIVE_PATH REL_INCLUDE_DIR "${${PNAME}_FULL_INSTALL_CMAKE_DIR}" "${${PNAME}_FULL_INSTALL_INCLUDE_DIR}" )
set( CONF_INCLUDE_DIRS "\${${PNAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
@@ -255,17 +353,17 @@ macro( ecbuild_install_project )
list( APPEND CONF_TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIR} )
endif()
endforeach()
-
+
set( _is_build_dir_export OFF )
configure_file( "${_template_config}" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" @ONLY )
install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${LNAME}-config.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" )
-
+
# install the export
-
+
if( ${PROJECT_NAME}_ALL_EXES OR ${PROJECT_NAME}_ALL_LIBS )
install( EXPORT ${CMAKE_PROJECT_NAME}-targets DESTINATION "${INSTALL_CMAKE_DIR}" )
endif()
-
+
else()
set( ${PNAME}_FOUND TRUE PARENT_SCOPE )
@@ -280,7 +378,10 @@ macro( ecbuild_install_project )
set( ${PNAME}_TPL_LIBRARIES ${${PNAME}_TPL_LIBRARIES} PARENT_SCOPE )
set( ${PNAME}_TPL_DEFINITIONS ${${PNAME}_TPL_DEFINITIONS} PARENT_SCOPE )
set( ${PNAME}_TPL_INCLUDE_DIRS ${${PNAME}_TPL_INCLUDE_DIRS} PARENT_SCOPE )
-
- endif()
+ set( ${PNAME}_FEATURES ${${PNAME}_FEATURES} PARENT_SCOPE )
+ foreach( _f ${${PNAME}_FEATURES} )
+ set( ${PNAME}_HAVE_${_f} ${${PNAME}_HAVE_${_f}} PARENT_SCOPE )
+ endforeach()
+ endif()
endmacro( ecbuild_install_project )
diff --git a/cmake/ecbuild_list_extra_search_paths.cmake b/cmake/ecbuild_list_extra_search_paths.cmake
index 7373486..719b1e7 100644
--- a/cmake/ecbuild_list_extra_search_paths.cmake
+++ b/cmake/ecbuild_list_extra_search_paths.cmake
@@ -8,13 +8,15 @@
############################################################################################
#
-# macro for adding search paths to CMAKE_PREFIX_PATH
-# for example the ECMWF /usr/local/apps paths
+# macro for adding search paths for a package to a given CMake variable
#
# usage: ecbuild_list_extra_search_paths( netcdf4 VARIABLE )
function( ecbuild_list_extra_search_paths pkg var )
+ message( DEPRECATION " ecbuild_list_extra_search_paths should no longer be"
+ " used and is going to be removed in a future version of ecBuild." )
+
# debug_var( pkg )
# debug_var( var )
@@ -23,75 +25,45 @@ function( ecbuild_list_extra_search_paths pkg var )
# PKG_PATH (upper case)
if( DEFINED ${_PKG}_PATH AND EXISTS ${${_PKG}_PATH} )
- message( "${_PKG}_PATH ${${_PKG}_PATH} exists " )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending ${_PKG}_PATH = ${${_PKG}_PATH} to ${var}")
list( APPEND ${var} ${${_PKG}_PATH} )
endif()
# ENV PKG_PATH (upper case)
if( DEFINED ENV{${_PKG}_PATH} AND EXISTS $ENV{${_PKG}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${_PKG}_PATH = $ENV{${_PKG}_PATH} to ${var}")
list( APPEND ${var} $ENV{${_PKG}_PATH} )
endif()
# pkg_PATH (lower case)
if( DEFINED ${pkg}_PATH AND EXISTS ${${pkg}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending ${pkg}_PATH = ${${pkg}_PATH} to ${var}")
list( APPEND ${var} ${${pkg}_PATH} )
endif()
# ENV pkg_PATH (lower case)
- if( DEFINED ${pkg}_PATH AND EXISTS ${${pkg}_PATH} )
- list( APPEND ${var} ${${pkg}_PATH} )
+ if( DEFINED ${pkg}_PATH AND EXISTS $ENV{${pkg}_PATH} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${pkg}_PATH = $ENV{${pkg}_PATH} to ${var}")
+ list( APPEND ${var} $ENV{${pkg}_PATH} )
endif()
# ENV PKG_DIR (upper case)
if( DEFINED ENV{${_PKG}_DIR} AND EXISTS $ENV{${_PKG}_DIR} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${_PKG}_DIR = $ENV{${_PKG}_DIR} to ${var}")
list( APPEND ${var} $ENV{${_PKG}_DIR} )
endif()
# ENV pkg_DIR (lower case)
if( DEFINED ENV{${pkg}_DIR} AND EXISTS $ENV{${pkg}_DIR} )
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): appending \$${pkg}_DIR = $ENV{${pkg}_DIR} to ${var}")
list( APPEND ${var} $ENV{${pkg}_DIR} )
endif()
- # directories under /usr/local/apps/${pkg}
-
- if( SEARCH_ECMWF_PATHS )
-
- foreach( _apps /usr/local/apps/${pkg} /usr/local/lib/metaps/lib/${pkg} )
-
- if( EXISTS ${_apps} )
-
- file( GLOB ps ${_apps}/[0-9]* )
- list( SORT ps )
- list( REVERSE ps ) # reversing will give us the newest versions first
- foreach( p ${ps} )
- if( IS_DIRECTORY ${p} )
- list( APPEND ${var} ${p} )
- if( EXISTS ${p}/LP64 )
- list( APPEND ${var} ${p}/LP64 )
- endif()
- endif()
- endforeach()
-
- foreach( p ${_apps} ${_apps}/current ${_apps}/stable ${_apps}/new ${_apps}/next ${_apps}/prev )
- if( EXISTS ${p} )
- list( APPEND ${var} ${p} )
- endif()
- if( EXISTS ${p}/LP64 )
- list( APPEND ${var} ${p}/LP64 )
- endif()
- endforeach()
-
- endif()
-
- endforeach()
-
- endif( SEARCH_ECMWF_PATHS )
-
# sanitize the list
if( ${var} )
@@ -100,6 +72,7 @@ function( ecbuild_list_extra_search_paths pkg var )
# define it out of the function
+ ecbuild_debug("ecbuild_list_extra_search_paths(${pkg}): setting ${var} to ${${var}}")
set( ${var} ${${var}} PARENT_SCOPE )
# debug_var( ${var} )
diff --git a/cmake/ecbuild_list_macros.cmake b/cmake/ecbuild_list_macros.cmake
index 5c10dd2..fcfc815 100644
--- a/cmake/ecbuild_list_macros.cmake
+++ b/cmake/ecbuild_list_macros.cmake
@@ -55,3 +55,36 @@ endfunction(MAP_INSERT)
function( MAP_GET _map _key _var )
set( ${_var} "${_${_map}_${_key}}" PARENT_SCOPE )
endfunction(MAP_GET)
+
+##############################################################################
+# function to remove items from a list that match a list of patterns
+#
+# examples:
+#
+# ecbuild_list_remove_pattern( mylist "foo;bar" VAR )
+#
+
+function(ecbuild_list_remove_pattern _list _patterns _var)
+
+#debug_var( _list )
+#debug_var( _patterns )
+#debug_var( _var )
+
+ foreach( _elem ${_list} )
+ set( _keep TRUE)
+ foreach( _pat ${_patterns} )
+ if( ${_elem} MATCHES ${_pat} )
+ set( _keep FALSE)
+ endif()
+ endforeach()
+ if( _keep )
+ list( APPEND _result ${_elem} )
+ endif()
+
+ endforeach()
+
+#debug_var( _result )
+
+ set( ${_var} "${_result}" PARENT_SCOPE )
+
+endfunction(ecbuild_list_remove_pattern)
diff --git a/cmake/ecbuild_log.cmake b/cmake/ecbuild_log.cmake
new file mode 100644
index 0000000..fbb2349
--- /dev/null
+++ b/cmake/ecbuild_log.cmake
@@ -0,0 +1,129 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+##############################################################################
+#.rst:
+#
+# Logging
+# =======
+#
+# ecBuild provides macros for logging based on a log level set by the user,
+# similar to the Python logging module:
+#
+# :ecbuild_debug: logs a ``STATUS`` message if log level <= ``DEBUG``
+# :ecbuild_info: logs a ``STATUS`` message if log level <= ``INFO``
+# :ecbuild_warn: logs a ``WARNING`` message if log level <= ``WARN``
+# :ecbuild_error: logs a ``SEND_ERROR`` message if log level <= ``ERROR``
+# :ecbuild_critical: logs a ``FATAL_ERROR`` message if log level <= ``CRITICAL``
+#
+# Input variables
+# ---------------
+#
+# CMake variables controlling logging behaviour:
+#
+# ECBUILD_LOG_LEVEL : string, one of DEBUG, INFO, WARN, ERROR, CRITICAL, OFF
+# set the desired log level, OFF to disable logging altogether
+#
+# ECBUILD_NO_COLOUR : bool
+# if set, does not colour log output (by default log output is coloured)
+#
+# Usage
+# -----
+#
+# The macros ``ecbuild_debug`` and ``ecbuild_info`` can be used to output
+# messages which are not printed by default. Many ecBuild macros use this
+# facility to log debugging hints. When debugging a CMake run, users can use
+# ``-DECBUILD_LOG_LEVEL=DEBUG`` to get detailed diagnostics.
+#
+##############################################################################
+
+# Define colour escape sequences (https://stackoverflow.com/a/19578320/396967)
+if(NOT (WIN32 OR ECBUILD_NO_COLOUR))
+ string(ASCII 27 Esc)
+ set(ColourReset "${Esc}[m")
+ set(ColourBold "${Esc}[1m")
+ set(Red "${Esc}[31m")
+ set(Green "${Esc}[32m")
+ set(Yellow "${Esc}[33m")
+ set(Blue "${Esc}[34m")
+ set(Magenta "${Esc}[35m")
+ set(Cyan "${Esc}[36m")
+ set(White "${Esc}[37m")
+ set(BoldRed "${Esc}[1;31m")
+ set(BoldGreen "${Esc}[1;32m")
+ set(BoldYellow "${Esc}[1;33m")
+ set(BoldBlue "${Esc}[1;34m")
+ set(BoldMagenta "${Esc}[1;35m")
+ set(BoldCyan "${Esc}[1;36m")
+ set(BoldWhite "${Esc}[1;37m")
+endif()
+
+set(ECBUILD_DEBUG 10)
+set(ECBUILD_INFO 20)
+set(ECBUILD_WARN 30)
+set(ECBUILD_ERROR 40)
+set(ECBUILD_CRITICAL 50)
+
+if( NOT DEFINED ECBUILD_LOG_LEVEL )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_WARN})
+elseif( NOT ECBUILD_LOG_LEVEL )
+ set(ECBUILD_LOG_LEVEL 60)
+elseif( ECBUILD_LOG_LEVEL STREQUAL "DEBUG" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_DEBUG})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "INFO" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_INFO})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "WARN" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_WARN})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "ERROR" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_ERROR})
+elseif( ECBUILD_LOG_LEVEL STREQUAL "CRITICAL" )
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_CRITICAL})
+else()
+ message(WARNING "Unknown log level ${ECBUILD_LOG_LEVEL} (valid are DEBUG, INFO, WARN, ERROR, CRITICAL) - using WARN")
+ set(ECBUILD_LOG_LEVEL ${ECBUILD_WARN})
+endif()
+
+##############################################################################
+
+macro( ecbuild_debug MSG )
+ if( ECBUILD_LOG_LEVEL LESS 11)
+ message(STATUS "${Blue}DEBUG - ${MSG}${ColourReset}")
+ endif()
+endmacro( ecbuild_debug )
+
+##############################################################################
+
+macro( ecbuild_info MSG )
+ if( ECBUILD_LOG_LEVEL LESS 21)
+ message(STATUS "${Green}INFO - ${MSG}${ColourReset}")
+ endif()
+endmacro( ecbuild_info )
+
+##############################################################################
+
+macro( ecbuild_warn MSG )
+ if( ECBUILD_LOG_LEVEL LESS 31)
+ message(WARNING "${Yellow}WARN - ${MSG}${ColourReset}")
+ endif()
+endmacro( ecbuild_warn )
+
+##############################################################################
+
+macro( ecbuild_error MSG )
+ if( ECBUILD_LOG_LEVEL LESS 41)
+ message(SEND_ERROR "${BoldRed}ERROR - ${MSG}${ColourReset}")
+ endif()
+endmacro( ecbuild_error )
+
+##############################################################################
+
+macro( ecbuild_critical MSG )
+ if( ECBUILD_LOG_LEVEL LESS 51)
+ message(FATAL_ERROR "${BoldMagenta}CRITICAL - ${MSG}${ColourReset}")
+ endif()
+endmacro( ecbuild_critical )
diff --git a/cmake/ecbuild_pkgconfig.cmake b/cmake/ecbuild_pkgconfig.cmake
index 8549d46..5bcca33 100644
--- a/cmake/ecbuild_pkgconfig.cmake
+++ b/cmake/ecbuild_pkgconfig.cmake
@@ -6,52 +6,10 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-#############################################################################################
-#
-# MACRO ecbuild_pkgconfig
-#
-# This macro creates a pkg-config file for the current project
-#
-# It takes following optional arguments:
-#
-# - FILENAME <filename>
-# The file that will be generated. Default value is the lowercase
-# name of the project with suffix ".pc" is used
-#
-# - NAME <name>
-# The name to be given to the package. Default value is the lowercase
-# name of the project
-#
-# - TEMPLATE <template>
-# The template configuration file to use. This is useful to create more
-# custom pkg-config files. Default is ${ECBUILD_CMAKE_DIR}/pkg-config.pc.in
-#
-# - URL <url>
-# The url of the package. Default is ${UPPERCASE_PROJECT_NAME}_URL
-#
-# - DESCRIPTION <description>
-# The description of the package. Default is ${UPPERCASE_PROJECT_NAME}_DESCRIPTION
-#
-# - LIBRARIES <libraries>
-# The package libraries. Default is ${UPPERCASE_PROJECT_NAME}_LIBRARIES
-# This is e.g. of the form "eckit;eckit_geometry"
-#
-# - IGNORE_INCLUDE_DIRS <include_dirs>
-# Ignore specified include directories
-#
-# - IGNORE_LIBRARIES <libraries>
-# Ignore specified libraries
-#
-# - LANGUAGES <languages>
-# List of languages used. If none given, all CMake_<lang>_COMPILER_LOAED languages
-# are added. Accepted languages: C CXX Fortran
-#
-# - NO_PRIVATE_INCLUDE_DIRS
-# Don't add include dirs of dependencies to Cflags. This is mainly useful
-# for Fortran only packages, when only the modules need to be added to Cflags
-#
-#############################################################################################
+##############################################################################
+# Write transitive list of library dependencies of each library in ${libraries}
+# to CMake variable ${dependencies}
function( ecbuild_library_dependencies dependencies libraries )
set( _libraries ${${libraries}} )
@@ -105,8 +63,10 @@ function( ecbuild_library_dependencies dependencies libraries )
endfunction(ecbuild_library_dependencies)
-#############################################################################################
+##############################################################################
+# Write list of include directories of each library in ${libraries}
+# to CMake variable ${dependencies}
function( ecbuild_include_dependencies dependencies libraries )
set( _libraries ${${libraries}} )
@@ -129,8 +89,10 @@ function( ecbuild_include_dependencies dependencies libraries )
endfunction(ecbuild_include_dependencies)
-#############################################################################################
+##############################################################################
+# Transform list of libraries in ${libraries}, ignoring any in ${ignore_libs},
+# and write pkg-config compatible string to CMake variable ${pkgconfig_libs}
function( ecbuild_pkgconfig_libs pkgconfig_libs libraries ignore_libs )
set( _libraries ${${libraries}} )
@@ -158,6 +120,9 @@ function( ecbuild_pkgconfig_libs pkgconfig_libs libraries ignore_libs )
get_filename_component( _name ${_lib} NAME_WE )
get_filename_component( _dir ${_lib} PATH )
+ if( TARGET ${_lib} )
+ get_target_property( _name ${_lib} OUTPUT_NAME )
+ endif()
if( NOT _name )
set( _name ${_lib} )
endif()
@@ -203,10 +168,11 @@ function( ecbuild_pkgconfig_libs pkgconfig_libs libraries ignore_libs )
endfunction(ecbuild_pkgconfig_libs)
+##############################################################################
-#############################################################################################
-
-
+# Transform list of include directories in ${INCLUDE_DIRS}, ignoring any in
+# ${ignore_includes} and ${${PNAME}_INCLUDE_DIRS}, and write pkg-config
+# compatible string to CMake variable ${INCLUDE}
function( ecbuild_pkgconfig_include INCLUDE INCLUDE_DIRS ignore_includes )
string( TOUPPER ${PROJECT_NAME} PNAME )
@@ -216,14 +182,17 @@ function( ecbuild_pkgconfig_include INCLUDE INCLUDE_DIRS ignore_includes )
list( APPEND ignore_include_dirs
"/usr/include"
${${PNAME}_INCLUDE_DIRS} # These are build-directory includes
+ ${CMAKE_SOURCE_DIR} # Ignore private includes referencing source tree
+ ${CMAKE_BINARY_DIR} # Ignore private includes referencing build tree
${_ignore_includes}
)
foreach( _incdir ${${INCLUDE_DIRS}} )
foreach( _ignore ${ignore_include_dirs} )
- if( "${_incdir}" STREQUAL "${_ignore}" )
+ if( "${_incdir}" MATCHES "${_ignore}" )
unset( _incdir )
+ break()
endif()
endforeach()
@@ -241,13 +210,100 @@ function( ecbuild_pkgconfig_include INCLUDE INCLUDE_DIRS ignore_includes )
endfunction(ecbuild_pkgconfig_include)
-
-#############################################################################################
+##############################################################################
+#.rst:
+#
+# ecbuild_pkgconfig
+# =================
+#
+# Create a pkg-config file for the current project. ::
+#
+# ecbuild_pkgconfig( [ NAME <name> ]
+# [ FILENAME <filename> ]
+# [ TEMPLATE <template> ]
+# [ URL <url> ]
+# [ DESCRIPTION <description> ]
+# [ LIBRARIES <lib1> [ <lib2> ... ] ]
+# [ IGNORE_INCLUDE_DIRS <dir1> [ <dir2> ... ] ]
+# [ IGNORE_LIBRARIES <lib1> [ <lib2> ... ] ]
+# [ LANGUAGES <language1> [ <language2> ... ] ]
+# [ VARIABLES <variable1> [ <variable2> ... ] ]
+# [ NO_PRIVATE_INCLUDE_DIRS ] )
+#
+# Options
+# -------
+#
+# NAME : optional, defaults to lower case name of the project
+# name to be given to the package
+#
+# FILENAME : optional, defaults to ``<NAME>.pc``
+# file to be generated, including .pc extension
+#
+# TEMPLATE : optional, defaults to ``${ECBUILD_CMAKE_DIR}/pkg-config.pc.in``
+# template configuration file to use
+#
+# This is useful to create customised pkg-config files.
+#
+# URL : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_URL``
+# url of the package
+#
+# DESCRIPTION : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_DESCRIPTION``
+# description of the package
+#
+# LIBRARIES : optional, defaults to ``${UPPERCASE_PROJECT_NAME}_LIBRARIES``
+# list of package libraries
+#
+# IGNORE_INCLUDE_DIRS : optional
+# list of include directories to ignore
+#
+# IGNORE_LIBRARIES : optional
+# list of libraries to ignore i.e. those are removed from ``LIBRARIES``
+#
+# VARIABLES : optional
+# list of additional CMake variables to export to the pkg-config file
+#
+# LANGUAGES : optional, defaults to all loaded languages
+# list of languages to use. Accepted languages: C CXX Fortran
+#
+# NO_PRIVATE_INCLUDE_DIRS
+# do not add include directories of dependencies to Cflags
+#
+# This is mainly useful for Fortran only packages, when only modules need
+# to be added to Cflags.
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables are used as default values for some of the
+# options listed above, where ``PNAME`` is the project name in upper case: ::
+#
+# :<PNAME>_LIBRARIES: list of libraries to export
+# :<PNAME>_DESCRIPTION: package description
+# :<PNAME>_URL: package URL
+# :<PNAME>_VERSION: package version
+# :<PNAME>_GIT_SHA1: Git revision
+#
+# Usage
+# -----
+#
+# It is good practice to provide a separate pkg-config file for each library a
+# package exports. This can be achieved as follows: ::
+#
+# foreach( _lib ${${PNAME}_LIBRARIES} )
+# if( TARGET ${_lib} )
+# ecbuild_pkgconfig( NAME ${_lib}
+# DESCRIPTION "..."
+# URL "..."
+# LIBRARIES ${_lib} )
+# endif()
+# endforeach()
+#
+##############################################################################
function( ecbuild_pkgconfig )
set( options REQUIRES NO_PRIVATE_INCLUDE_DIRS )
- set( single_value_args FILEPATH NAME TEMPLATE URL DESCRIPTION )
+ set( single_value_args FILENAME NAME TEMPLATE URL DESCRIPTION )
set( multi_value_args LIBRARIES IGNORE_INCLUDE_DIRS IGNORE_LIBRARIES VARIABLES LANGUAGES )
cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
@@ -331,8 +387,8 @@ function( ecbuild_pkgconfig )
set( PKGCONFIG_NAME ${_PAR_NAME} )
endif()
- if( NOT _PAR_FILEPATH )
- set( _PAR_FILEPATH "${PKGCONFIG_NAME}.pc" )
+ if( NOT _PAR_FILENAME )
+ set( _PAR_FILENAME "${PKGCONFIG_NAME}.pc" )
endif()
set( PKGCONFIG_DESCRIPTION ${${PNAME}_DESCRIPTION} )
@@ -355,11 +411,11 @@ function( ecbuild_pkgconfig )
endforeach()
endif()
- configure_file( ${_PAR_TEMPLATE} "${CMAKE_BINARY_DIR}/${_PAR_FILEPATH}" @ONLY )
- message( STATUS "pkg-config file created: ${_PAR_FILEPATH}" )
+ configure_file( ${_PAR_TEMPLATE} "${CMAKE_BINARY_DIR}/${_PAR_FILENAME}" @ONLY )
+ message( STATUS "pkg-config file created: ${_PAR_FILENAME}" )
- install( FILES ${CMAKE_BINARY_DIR}/${_PAR_FILEPATH}
- DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/
+ install( FILES ${CMAKE_BINARY_DIR}/${_PAR_FILENAME}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/pkgconfig/
COMPONENT utilities )
endfunction(ecbuild_pkgconfig)
diff --git a/cmake/ecbuild_policies.cmake b/cmake/ecbuild_policies.cmake
new file mode 100644
index 0000000..06f856b
--- /dev/null
+++ b/cmake/ecbuild_policies.cmake
@@ -0,0 +1,63 @@
+# (C) Copyright 1996-2015 ECMWF.
+#
+# This software is licensed under the terms of the Apache Licence Version 2.0
+# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
+# In applying this licence, ECMWF does not waive the privileges and immunities
+# granted to it by virtue of its status as an intergovernmental organisation
+# nor does it submit to any jurisdiction.
+
+###############################################################################
+# define cmake policies
+#
+# NOTE: This file needs to be included with NO_POLICY_SCOPE or it will have no
+# effect!
+# NOTE: Policies 1 through 17 will be set to NEW by requiring CMake 2.8.4 i.e.
+# calling cmake_minimum_required( VERSION 2.8.4 FATAL_ERROR )
+
+# allow for empty spaces around library names
+if( POLICY CMP0004 )
+ cmake_policy( SET CMP0004 OLD )
+endif()
+
+# Allow use of the LOCATION target property.
+if( POLICY CMP0026 )
+ cmake_policy( SET CMP0026 OLD )
+endif()
+
+# for macosx use @rpath in a target’s install name
+if( POLICY CMP0042 )
+ cmake_policy( SET CMP0042 NEW )
+ set( CMAKE_MACOSX_RPATH ON )
+endif()
+
+# Error on non-existent target in get_target_property
+if( POLICY CMP0045 )
+ cmake_policy( SET CMP0045 NEW )
+endif()
+
+# Error on non-existent dependency in add_dependencies
+if( POLICY CMP0046 )
+ cmake_policy( SET CMP0046 NEW )
+endif()
+
+# Do not manage VERSION variables in project command
+if( POLICY CMP0048 )
+ cmake_policy( SET CMP0048 OLD )
+endif()
+
+# Disallow add_custom_command SOURCE signatures
+if( POLICY CMP0050 )
+ cmake_policy( SET CMP0050 NEW )
+endif()
+
+# Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES
+if( POLICY CMP0052 )
+ cmake_policy( SET CMP0052 NEW )
+endif()
+
+# inside if() don't dereference variables if they are quoted
+# e.g. "VAR" is not dereferenced
+# "${VAR}" is dereference only once
+if( POLICY CMP0054 )
+ cmake_policy( SET CMP0054 NEW )
+endif()
diff --git a/cmake/ecbuild_print_summary.cmake b/cmake/ecbuild_print_summary.cmake
index 193bf1f..b3cddf0 100644
--- a/cmake/ecbuild_print_summary.cmake
+++ b/cmake/ecbuild_print_summary.cmake
@@ -6,110 +6,101 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
+##############################################################################
+#.rst:
+#
+# ecbuild_print_summary
+# =====================
+#
+# Print a summary of the project, build environment and enabled features. ::
+#
+# ecbuild_print_summary()
+#
+# If ``project_summary.cmake`` exist in the source root directory, a project
+# summary is printed by including this file.
+#
+# For a top level project, a summary of the build environment and a feature
+# summary are also printed.
+#
+##############################################################################
+
macro( ecbuild_print_summary )
- if( EXISTS ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+ if( EXISTS ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+
+ message( STATUS "---------------------------------------------------------" )
+ message( STATUS "Project ${PROJECT_NAME} summary" )
+ message( STATUS "---------------------------------------------------------" )
+
+ include( ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+
+ endif()
+
+ if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+
+ ecbuild_define_links_target()
- message( STATUS "---------------------------------------------------------" )
- message( STATUS "Project ${PROJECT_NAME} summary" )
- message( STATUS "---------------------------------------------------------" )
+ get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
- include( ${PROJECT_SOURCE_DIR}/project_summary.cmake )
+ message( STATUS "---------------------------------------------------------" )
+ if( NOT ${DEVELOPER_MODE} )
+ message( STATUS "Build summary" )
+ else()
+ message( STATUS "Build summary -- ( DEVELOPER_MODE )" )
+ endif()
+ message( STATUS "---------------------------------------------------------" )
+ message( STATUS "system : [${BUILD_SITE}] [${CMAKE_SYSTEM}] [${EC_OS_NAME}.${EC_OS_BITS}]" )
+ message( STATUS "processor : [${CMAKE_SYSTEM_PROCESSOR}]" )
+ if( EC_BIG_ENDIAN )
+ message( STATUS "endiness : Big Endian -- IEEE [${IEEE_BE}]" )
+ endif()
+ if( EC_LITTLE_ENDIAN )
+ message( STATUS "endiness : Little Endian -- IEEE [${IEEE_LE}]" )
+ endif()
+ message( STATUS "build type : [${CMAKE_BUILD_TYPE}]" )
+ message( STATUS "timestamp : [${EC_BUILD_TIMESTAMP}]" )
+ message( STATUS "install prefix : [${CMAKE_INSTALL_PREFIX}]" )
+ if( EC_LINK_DIR )
+ message( STATUS "links prefix : [${EC_LINK_DIR}]" )
endif()
+ message( STATUS "---------------------------------------------------------" )
- if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
-
- ecbuild_define_links_target()
-
- get_property( langs GLOBAL PROPERTY ENABLED_LANGUAGES )
-
- message( STATUS "---------------------------------------------------------" )
- if( NOT ${DEVELOPER_MODE} )
- message( STATUS "Build summary" )
- else()
- message( STATUS "Build summary -- ( DEVELOPER_MODE )" )
- endif()
- message( STATUS "---------------------------------------------------------" )
-
- message( STATUS "system : [${BUILD_SITE}] [${CMAKE_SYSTEM}] [${EC_OS_NAME}.${EC_OS_BITS}]" )
- message( STATUS "processor : [${CMAKE_SYSTEM_PROCESSOR}]" )
- if( EC_BIG_ENDIAN )
- message( STATUS "endiness : Big Endian -- IEEE [${IEEE_BE}]" )
- endif()
- if( EC_LITTLE_ENDIAN )
- message( STATUS "endiness : Little Endian -- IEEE [${IEEE_LE}]" )
- endif()
- message( STATUS "build type : [${CMAKE_BUILD_TYPE}]" )
- message( STATUS "timestamp : [${EC_BUILD_TIMESTAMP}]" )
- message( STATUS "install prefix : [${CMAKE_INSTALL_PREFIX}]" )
- if( EC_LINK_DIR )
- message( STATUS "links prefix : [${EC_LINK_DIR}]" )
- endif()
- message( STATUS "---------------------------------------------------------" )
-
- foreach( lang ${langs} )
- message( STATUS "${lang} -- ${CMAKE_${lang}_COMPILER_ID} ${CMAKE_${lang}_COMPILER_VERSION}" )
- message( STATUS " compiler : ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
- message( STATUS " link flags : ${CMAKE_${lang}_LINK_FLAGS}" )
- endforeach()
-
- message( STATUS "linker : ${CMAKE_LINKER}")
- message( STATUS "ar : ${CMAKE_AR}")
- message( STATUS "ranlib : ${CMAKE_RANLIB}")
- message( STATUS "link flags" )
- message( STATUS " executable [${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXEC_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS " shared lib [${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS " static lib [${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
- message( STATUS "install rpath : ${CMAKE_INSTALL_RPATH}" )
-
- get_directory_property( defs COMPILE_DEFINITIONS )
-
- message( STATUS "common definitions: ${defs}" )
-
- message( STATUS "---------------------------------------------------------" )
-
- ### FEATURE SUMMARY
-
- # debug_var( CMAKE_VERSION )
- if( ${CMAKE_VERSION} VERSION_LESS "2.8.6" )
- feature_summary( WHAT ALL )
- else()
- feature_summary( WHAT ALL INCLUDE_QUIET_PACKAGES )
- endif()
-
- ### WARNINGS
+ foreach( lang ${langs} )
+ message( STATUS "${lang} -- ${CMAKE_${lang}_COMPILER_ID} ${CMAKE_${lang}_COMPILER_VERSION}" )
+ message( STATUS " compiler : ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_FLAGS} ${CMAKE_${lang}_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}" )
+ message( STATUS " link flags : ${CMAKE_${lang}_LINK_FLAGS}" )
+ endforeach()
- # issue warnings / errors in case there are unused project files
- ecbuild_warn_unused_files()
+ message( STATUS "linker : ${CMAKE_LINKER}")
+ message( STATUS "ar : ${CMAKE_AR}")
+ message( STATUS "ranlib : ${CMAKE_RANLIB}")
+ message( STATUS "link flags" )
+ message( STATUS " executable [${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ message( STATUS " shared lib [${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ message( STATUS " static lib [${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_CAPS}}]" )
+ message( STATUS "install rpath : ${CMAKE_INSTALL_RPATH}" )
+
+ get_directory_property( defs COMPILE_DEFINITIONS )
- # issue a warning that 'make install' mighty be broken for old cmakes
- if( ${CMAKE_VERSION} VERSION_LESS "2.8.3" )
-
- message( STATUS " +++ WARNING +++ WARNING +++ WARNING +++" )
- message( STATUS " +++ " )
- message( STATUS " +++ This CMake version [${CMAKE_VERSION}] is rather OLD !!" )
- message( STATUS " +++ " )
- message( STATUS " +++ We work hard to keep CMake backward compatibility (support >= 2.6.4)" )
- message( STATUS " +++ but there are some limits inherent to older versions." )
- message( STATUS " +++ " )
- message( STATUS " +++ You will be able to build the software... " )
- message( STATUS " +++ " )
- message( STATUS " +++ But: " )
- message( STATUS " +++ * the 'make install' target most likely will NOT WORK" )
- message( STATUS " +++ * if you want to install these binaries you might need to copy them by yourself" )
- message( STATUS " +++ * the binaries are in '${CMAKE_BINARY_DIR}' /lib and /bin" )
- message( STATUS " +++ * copying headers will take substantially more work, and you might end up copying files that won't be needed" )
- message( STATUS " +++ " )
- message( STATUS " +++ Therefore, we recommend that you: " )
- message( STATUS " +++ * upgrade to a newer CMake with version at least >= 2.8.3" )
- message( STATUS " +++ * remove this build directory '${CMAKE_BINARY_DIR}'" )
- message( STATUS " +++ * rerun a newer cmake on an new empty build directory" )
- message( STATUS " +++ " )
- message( STATUS " +++ WARNING +++ WARNING +++ WARNING +++" )
+ message( STATUS "common definitions: ${defs}" )
+ message( STATUS "---------------------------------------------------------" )
+
+ ### FEATURE SUMMARY
+
+ # debug_var( CMAKE_VERSION )
+ if( ${CMAKE_VERSION} VERSION_LESS "2.8.6" )
+ feature_summary( WHAT ALL )
+ else()
+ feature_summary( WHAT ALL INCLUDE_QUIET_PACKAGES )
endif()
- endif( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
+ ### WARNINGS
+
+ # issue warnings / errors in case there are unused project files
+ ecbuild_warn_unused_files()
+
+ endif( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
endmacro( ecbuild_print_summary )
diff --git a/cmake/ecbuild_project_files.cmake b/cmake/ecbuild_project_files.cmake
index f304772..162a625 100644
--- a/cmake/ecbuild_project_files.cmake
+++ b/cmake/ecbuild_project_files.cmake
@@ -16,30 +16,29 @@ macro( ecbuild_find_files_recursive aFileList )
list( APPEND ecbuild_project_extensions c cc cpp cxx ) # for the moment skip ( h hh )
-# first find all the files in the directory
foreach( aExt ${ecbuild_project_extensions} )
-
- file( GLOB_RECURSE listFilesWithExt *.${aExt})
-
- list( LENGTH listFilesWithExt sizeFilesWithExt )
- if( sizeFilesWithExt GREATER 0 )
- set( ${aFileList} ${${aFileList}} ${listFilesWithExt} )
- endif()
-
+ set( globPatterns ${globPatterns} *.${aExt} )
endforeach()
+# This globs for only one pattern at a time
+# Shell extglob patterns are unfortunately not supported.
+file( GLOB_RECURSE ${aFileList} ${globPatterns} )
+
endmacro()
##############################################################################
# finds the unused files on all the project
function( ecbuild_find_project_files )
- ecbuild_find_files_recursive( cwdFiles )
+ # Only do this if we actually care to warn about unused files
+ if( CHECK_UNUSED_FILES )
+ ecbuild_find_files_recursive( cwdFiles )
- # this list will be kept
- set( EC_PROJECT_FILES ${EC_PROJECT_FILES} ${cwdFiles} CACHE INTERNAL "" )
- # this list will be progressevely emptied
- set( EC_UNUSED_FILES ${EC_UNUSED_FILES} ${cwdFiles} CACHE INTERNAL "" )
+ # this list will be kept
+ set( EC_PROJECT_FILES ${EC_PROJECT_FILES} ${cwdFiles} CACHE INTERNAL "" )
+ # this list will be progressevely emptied
+ set( EC_UNUSED_FILES ${EC_UNUSED_FILES} ${cwdFiles} CACHE INTERNAL "" )
+ endif()
endfunction()
@@ -47,27 +46,30 @@ endfunction()
# removed used files from unused list
macro( ecbuild_declare_project_files )
- foreach( _afile ${ARGV} )
+ # Only do this if we actually care to warn about unused files
+ if( CHECK_UNUSED_FILES )
+ foreach( _afile ${ARGV} )
- # debug_var( _afile )
+ # debug_var( _afile )
- get_property( _src_gen SOURCE ${_afile} PROPERTY GENERATED )
+ get_property( _src_gen SOURCE ${_afile} PROPERTY GENERATED )
- if( NOT _src_gen )
+ if( NOT _src_gen )
- get_filename_component( _abspath ${_afile} ABSOLUTE )
+ get_filename_component( _abspath ${_afile} ABSOLUTE )
- # check for existance of all declared files
- if( EXISTS ${_abspath} )
- list( REMOVE_ITEM EC_UNUSED_FILES ${_abspath} )
- else()
- message( FATAL_ERROR "In directory ${CMAKE_CURRENT_SOURCE_DIR} file ${_afile} was declared in CMakeLists.txt but not found" )
- endif()
- endif()
+ # check for existance of all declared files
+ if( EXISTS ${_abspath} )
+ list( REMOVE_ITEM EC_UNUSED_FILES ${_abspath} )
+ else()
+ message( FATAL_ERROR "In directory ${CMAKE_CURRENT_SOURCE_DIR} file ${_afile} was declared in CMakeLists.txt but not found" )
+ endif()
+ endif()
- endforeach()
+ endforeach()
- # rewrite the unused file list in cache
- set( EC_UNUSED_FILES ${EC_UNUSED_FILES} CACHE INTERNAL "unused files" )
+ # rewrite the unused file list in cache
+ set( EC_UNUSED_FILES ${EC_UNUSED_FILES} CACHE INTERNAL "unused files" )
+ endif()
endmacro()
diff --git a/cmake/ecbuild_requires_macro_version.cmake b/cmake/ecbuild_requires_macro_version.cmake
index dbdcc05..6c73fe7 100644
--- a/cmake/ecbuild_requires_macro_version.cmake
+++ b/cmake/ecbuild_requires_macro_version.cmake
@@ -6,6 +6,18 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
+##############################################################################
+#.rst:
+#
+# ecbuild_requires_macro_version
+# ==============================
+#
+# Check that the ecBuild version satisfied a given minimum version or fail. ::
+#
+# ecbuild_requires_macro_version( <minimum-version> )
+#
+##############################################################################
+
macro( ecbuild_requires_macro_version req_vrs )
if( ECBUILD_MACRO_VERSION VERSION_LESS ${req_vrs} )
diff --git a/cmake/ecbuild_separate_sources.cmake b/cmake/ecbuild_separate_sources.cmake
index 71d56b3..94aa182 100644
--- a/cmake/ecbuild_separate_sources.cmake
+++ b/cmake/ecbuild_separate_sources.cmake
@@ -7,7 +7,36 @@
# does it submit to any jurisdiction.
##############################################################################
-# macro for separating sources sccording to language
+#.rst:
+#
+# ecbuild_separate_sources
+# ========================
+#
+# Separate a given list of sources according to language. ::
+#
+# ecbuild_separate_sources( TARGET <name>
+# SOURCES <source1> [ <source2> ... ] )
+#
+# Options
+# -------
+#
+# TARGET : required
+# base name for the CMake output variables to set
+#
+# SOURCES : required
+# list of source files to separate
+#
+# Output variables
+# ----------------
+#
+# If any file of the following group of extensions is present in the list of
+# sources, the corresponding CMake variable is set:
+#
+# :<target>_h_srcs: list of sources with extension .h, .hxx, .hh, .hpp, .H
+# :<target>_c_srcs: list of sources with extension .c
+# :<target>_cxx_srcs: list of sources with extension .cc, .cxx, .cpp, .C
+# :<target>_f_srcs: list of sources with extension .f, .F, .for, f77, .f90, .f95
+#
##############################################################################
macro( ecbuild_separate_sources )
@@ -60,4 +89,3 @@ macro( ecbuild_separate_sources )
# debug_var( ${_PAR_TARGET}_f_srcs )
endmacro( ecbuild_separate_sources )
-
diff --git a/cmake/ecbuild_setup_test_framework.cmake b/cmake/ecbuild_setup_test_framework.cmake
index 86f026e..538a433 100644
--- a/cmake/ecbuild_setup_test_framework.cmake
+++ b/cmake/ecbuild_setup_test_framework.cmake
@@ -1,42 +1,41 @@
ecbuild_add_option( FEATURE TESTS
- DEFAULT ON
- DESCRIPTION "Enable the unit tests" )
+ DEFAULT ON
+ DESCRIPTION "Enable the unit tests" )
if( ENABLE_TESTS )
- # Try to find compiled boost
+ # Try to find compiled boost
- if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
- set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
- endif()
+ # BOOST_ROOT or BOOSTROOT should take precedence on the search for location
+ if( BOOST_ROOT OR BOOSTROOT OR DEFINED ENV{BOOST_ROOT} OR DEFINED ENV{BOOSTROOT} )
+ set( CMAKE_PREFIX_PATH ${BOOST_ROOT} ${BOOSTROOT} $ENV{BOOST_ROOT} $ENV{BOOSTROOT} ${CMAKE_PREFIX_PATH} )
+ endif()
- ecbuild_add_extra_search_paths( boost ) # also respects BOOST_ROOT
+ set( Boost_USE_MULTITHREADED ON )
+ # set( Boost_DEBUG ON )
- set( Boost_USE_MULTITHREADED ON )
-# set( Boost_DEBUG ON )
+ find_package( Boost 1.47.0 COMPONENTS unit_test_framework )
- find_package( Boost 1.47.0 COMPONENTS unit_test_framework )
+ set( ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" )
- set( ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" )
+ if( Boost_FOUND AND Boost_UNIT_TEST_FRAMEWORK_LIBRARY )
- if( Boost_FOUND AND Boost_UNIT_TEST_FRAMEWORK_LIBRARY )
+ set( HAVE_BOOST_UNIT_TEST 1 )
+ set( BOOST_UNIT_TEST_FRAMEWORK_LINKED 1 )
- set( HAVE_BOOST_UNIT_TEST 1 )
- set( BOOST_UNIT_TEST_FRAMEWORK_LINKED 1 )
+ message( STATUS "Using Boost for unit tests:\n INC [${Boost_INCLUDE_DIRS}]\n LIB [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" )
- # message( STATUS "Boost unit test framework -- FOUND [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" )
+ else()
- else()
+ message( STATUS "Boost unit test framework -- NOT FOUND" )
- message( STATUS "Boost unit test framework -- NOT FOUND" )
+ set( HAVE_BOOST_UNIT_TEST 0 )
- set( HAVE_BOOST_UNIT_TEST 0 )
+ # set( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY 1 )
+ # comment out this when ecbuild packs boost unit test inside...
+ # list( APPEND ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/contrib/boost-1.55/include" )
+ # set( HAVE_BOOST_UNIT_TEST 1 )
- # set( BOOST_UNIT_TEST_FRAMEWORK_HEADER_ONLY 1 )
- # comment out this when ecbuild packs boost unit test inside...
- # list( APPEND ECBUILD_BOOST_HEADER_DIRS "${CMAKE_CURRENT_LIST_DIR}/contrib/boost-1.55/include" )
- # set( HAVE_BOOST_UNIT_TEST 1 )
-
- endif()
+ endif()
endif()
diff --git a/cmake/ecbuild_system.cmake b/cmake/ecbuild_system.cmake
index 939d92e..fc07bf5 100644
--- a/cmake/ecbuild_system.cmake
+++ b/cmake/ecbuild_system.cmake
@@ -10,19 +10,19 @@
# disallow in-source build
if( EXISTS ${CMAKE_SOURCE_DIR}/CMakeCache.txt ) # check for failed attempts to build within the source tree
- message( FATAL_ERROR "Project ${PROJECT_NAME} contains a CMakeCache.txt inside source tree [${CMAKE_SOURCE_DIR}/CMakeCache.txt].\n Please remove it and
- make sure that source tree is prestine and clean of unintended files, before retrying." )
+ message( FATAL_ERROR "Project ${PROJECT_NAME} contains a CMakeCache.txt inside source tree [${CMAKE_SOURCE_DIR}/CMakeCache.txt].\n Please remove it and
+ make sure that source tree is prestine and clean of unintended files, before retrying." )
endif()
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
if(${srcdir} STREQUAL ${bindir})
- message("######################################################")
- message("You are attempting to build in your source directory (${srcdir}).")
- message("You must run cmake from a different build directory.")
- message("######################################################")
- message( FATAL_ERROR "${PROJECT_NAME} requires an out of source build.\n Please create a separate build directory and run 'cmake path/to/project [options]' from there.")
+ message("######################################################")
+ message("You are attempting to build in your source directory (${srcdir}).")
+ message("You must run cmake from a different build directory.")
+ message("######################################################")
+ message( FATAL_ERROR "${PROJECT_NAME} requires an out of source build.\n Please create a separate build directory and run 'cmake path/to/project [options]' from there.")
endif()
########################################################################################################
@@ -30,7 +30,7 @@ endif()
set( ECBUILD_CMAKE_MINIMUM "2.8.4" )
if( ${CMAKE_VERSION} VERSION_LESS ${ECBUILD_CMAKE_MINIMUM} )
- message(FATAL_ERROR "${PROJECT_NAME} requires at least CMake ${ECBUILD_CMAKE_MINIMUM} -- you are using ${CMAKE_COMMAND} [${CMAKE_VERSION}]\n Please, get a newer version of CMake @ www.cmake.org" )
+ message(FATAL_ERROR "${PROJECT_NAME} requires at least CMake ${ECBUILD_CMAKE_MINIMUM} -- you are using ${CMAKE_COMMAND} [${CMAKE_VERSION}]\n Please, get a newer version of CMake @ www.cmake.org" )
endif()
set( ECBUILD_MACROS_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "where ecbuild system is" )
@@ -39,243 +39,200 @@ include( "${ECBUILD_MACROS_DIR}/VERSION.cmake" )
set( ecbuild_VERSION_STR "${ECBUILD_VERSION_STR}" )
-########################################################################################################
-# define cmake policies
-
-# Included scripts don't automatic cmake_policy PUSH and POP
-
-if( POLICY CMP0011 )
- cmake_policy( SET CMP0011 OLD )
-endif()
-
-# Allow use of the LOCATION target property.
-
-if( POLICY CMP0026 )
- cmake_policy( SET CMP0026 OLD )
-endif()
-
-# for macosx use @rpath in a target’s install name
-
-if( POLICY CMP0042 )
- cmake_policy( SET CMP0042 NEW )
- set( CMAKE_MACOSX_RPATH ON )
-endif()
-
-# Error on non-existent target in get_target_property
+# Set policies
+include( ecbuild_policies NO_POLICY_SCOPE )
-if( POLICY CMP0045 )
- cmake_policy( SET CMP0045 NEW )
-endif()
+# set capitalised project name
-# Error on non-existent target in get_target_property
-
-if( POLICY CMP0046 )
- cmake_policy( SET CMP0046 NEW )
-endif()
-
-# Error on non-existent dependency in add_dependencies
-
-if( POLICY CMP0046 )
- cmake_policy( SET CMP0050 NEW )
-endif()
-
-# Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES
-
-if( POLICY CMP0052 )
- cmake_policy( SET CMP0052 NEW )
-endif()
-
-# inside if() don't dereference variables if they are quoted
-# e.g. "VAR" is not dereferenced
-# "${VAR}" is dereference only once
-
-if( POLICY CMP0054 )
- cmake_policy( SET CMP0054 NEW )
-endif()
+string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_CAPS )
+string( TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWCASE )
########################################################################################################
# include our cmake macros, but only do so if this is the top project
if( PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME )
- # hostname of where we build
+ # hostname of where we build
- site_name( BUILD_SITE )
- mark_as_advanced( BUILD_SITE )
- mark_as_advanced( BUILD_TESTING )
+ site_name( BUILD_SITE )
+ mark_as_advanced( BUILD_SITE )
+ mark_as_advanced( BUILD_TESTING )
- set( ECBUILD_PROJECTS "" CACHE INTERNAL "list of ecbuild (sub)projects that use ecbuild" )
+ set( ECBUILD_PROJECTS "" CACHE INTERNAL "list of ecbuild (sub)projects that use ecbuild" )
- message( STATUS "ecbuild ${ecbuild_VERSION_STR}\t${ECBUILD_MACROS_DIR}" )
- message( STATUS "cmake ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}\t${CMAKE_COMMAND}" )
+ message( STATUS "ecbuild ${ecbuild_VERSION_STR}\t${ECBUILD_MACROS_DIR}" )
+ message( STATUS "cmake ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}\t${CMAKE_COMMAND}" )
- if( CMAKE_TOOLCHAIN_FILE )
- message( STATUS "toolchain ${CMAKE_TOOLCHAIN_FILE}" )
- endif()
+ if( CMAKE_TOOLCHAIN_FILE )
+ message( STATUS "toolchain ${CMAKE_TOOLCHAIN_FILE}" )
+ endif()
- if( ECBUILD_CACHE )
- include( ${ECBUILD_CACHE} )
+ if( ECBUILD_CACHE )
+ include( ${ECBUILD_CACHE} )
message( STATUS "cache ${ECBUILD_CACHE}" )
- endif()
+ endif()
- message( STATUS "---------------------------------------------------------" )
+ message( STATUS "---------------------------------------------------------" )
- # clear the build dir exported targets file (only on the top project)
+ # clear the build dir exported targets file (only on the top project)
- set( TOP_PROJECT_TARGETS_FILE "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}-targets.cmake" CACHE INTERNAL "" )
- file( REMOVE ${TOP_PROJECT_TARGETS_FILE} )
+ set( TOP_PROJECT_TARGETS_FILE "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}-targets.cmake" CACHE INTERNAL "" )
+ file( REMOVE ${TOP_PROJECT_TARGETS_FILE} )
- # add backport support for versions up too 2.8.4
- if( ${CMAKE_VERSION} VERSION_LESS "2.8" )
- set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/2.8" ${CMAKE_MODULE_PATH} )
- endif()
+ # add backport support for versions up too 2.8.4
+ if( ${CMAKE_VERSION} VERSION_LESS "2.8" )
+ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/2.8" ${CMAKE_MODULE_PATH} )
+ endif()
- # add extra macros from external contributions
- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib" )
+ # add extra macros from external contributions
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib" )
- # would bring FindEigen in, so for the moment keep it out
- # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib/GreatCMakeCookOff" )
+ # would bring FindEigen in, so for the moment keep it out
+ # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/contrib/GreatCMakeCookOff" )
- include(CTest) # add cmake testing support
- enable_testing()
+ include(CTest) # add cmake testing support
+ enable_testing()
- # keep this until we modify the meaning to 'check' if installation worked
- add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} -V )
+ # keep this until we modify the meaning to 'check' if installation worked
+ add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} -V )
- ############################################################################################
- # define valid build types
+ ############################################################################################
+ # define valid build types
- include(ecbuild_define_build_types)
+ include(ecbuild_define_build_types)
- ############################################################################################
- # add cmake macros
+ ############################################################################################
+ # add cmake macros
- include(AddFileDependencies)
+ include(AddFileDependencies)
- include(CheckTypeSize)
- include(CheckIncludeFile)
- include(CheckIncludeFiles)
+ include(CheckTypeSize)
+ include(CheckIncludeFile)
+ include(CheckIncludeFiles)
- include(CheckFunctionExists)
- include(CheckSymbolExists)
+ include(CheckFunctionExists)
+ include(CheckSymbolExists)
- include(CheckCCompilerFlag)
- include(CheckCSourceCompiles)
- include(CheckCSourceRuns)
+ include(CheckCCompilerFlag)
+ include(CheckCSourceCompiles)
+ include(CheckCSourceRuns)
- include(CMakeParseArguments)
+ include(CMakeParseArguments)
- # include(CMakePrintSystemInformation) # available in cmake 2.8.4
+ # include(CMakePrintSystemInformation) # available in cmake 2.8.4
- if( CMAKE_CXX_COMPILER_LOADED )
- include(CheckIncludeFileCXX)
- include(CheckCXXCompilerFlag)
- include(CheckCXXSourceCompiles)
- include(CheckCXXSourceRuns)
- endif()
+ if( CMAKE_CXX_COMPILER_LOADED )
+ include(CheckIncludeFileCXX)
+ include(CheckCXXCompilerFlag)
+ include(CheckCXXSourceCompiles)
+ include(CheckCXXSourceRuns)
+ endif()
- if( CMAKE_Fortran_COMPILER_LOADED )
+ if( CMAKE_Fortran_COMPILER_LOADED )
set( CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/module CACHE PATH "directory for all fortran modules." )
- include(CheckFortranFunctionExists)
- if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
- include(FortranCInterface)
- endif()
- set( EC_HAVE_FORTRAN 1 )
- endif()
-
- include(FeatureSummary) # support features in cmake
-
- include(TestBigEndian)
-
- ############################################################################################
- # backport of cmake > 2.8.4 functions
-
- if( "${CMAKE_VERSION}" VERSION_LESS "2.8.6" )
- include( ${CMAKE_CURRENT_LIST_DIR}/2.8/CMakePushCheckState.cmake )
- else()
- include(CMakePushCheckState)
- endif()
-
- ############################################################################################
- # add our macros
-
- include( ecbuild_debug_var )
- include( ecbuild_list_macros )
-
- include( ecbuild_check_c_source )
-
- if( CMAKE_CXX_COMPILER_LOADED )
- include( ecbuild_check_cxx_source )
- include( ecbuild_check_cxx11 )
- endif()
-
- if( CMAKE_Fortran_COMPILER_LOADED )
- include( ecbuild_check_fortran_source )
- endif()
-
- include( ecbuild_requires_macro_version )
- include( ecbuild_get_date )
- include( ecbuild_add_persistent )
- include( ecbuild_generate_config_headers )
- include( ecbuild_generate_rpc )
- include( ecbuild_generate_yy )
- include( ecbuild_echo_targets )
- include( ecbuild_add_option )
- include( ecbuild_add_library )
- include( ecbuild_add_executable )
- include( ecbuild_append_to_rpath )
- include( ecbuild_get_test_data )
- include( ecbuild_add_cxx11_flags )
- include( ecbuild_add_test )
- include( ecbuild_add_resources )
- include( ecbuild_get_resources )
- include( ecbuild_project_files )
- include( ecbuild_declare_project )
- include( ecbuild_install_package )
- include( ecbuild_separate_sources )
- include( ecbuild_find_package )
- include( ecbuild_use_package )
- include( ecbuild_list_extra_search_paths )
- include( ecbuild_add_extra_search_paths )
- include( ecbuild_print_summary )
- include( ecbuild_warn_unused_files )
- include( ecbuild_find_mpi )
- include( ecbuild_find_omp )
- include( ecbuild_find_perl )
- include( ecbuild_find_python )
- include( ecbuild_find_lexyacc )
- include( ecbuild_find_fortranlibs )
- include( ecbuild_enable_fortran )
- include( ecbuild_check_c_source )
- include( ecbuild_check_cxx_source )
- include( ecbuild_check_fortran_source )
- include( ecbuild_bundle )
- include( ecbuild_pkgconfig )
- include( ecbuild_cache )
-
- include( ${CMAKE_CURRENT_LIST_DIR}/contrib/GetGitRevisionDescription.cmake )
-
- ############################################################################################
- # kickstart the build system
-
- ecbuild_prepare_cache()
- include( ecbuild_define_options ) # define build options
- include( ecbuild_check_compiler ) # check for compiler characteristics
- include( ecbuild_check_os ) # check for os characteristics
- include( ecbuild_check_functions ) # check for available functions
- include( ecbuild_define_paths ) # define installation paths
- include( ecbuild_links_target ) # define the links target
- include( ecbuild_setup_test_framework ) # setup test framework
- ecbuild_flush_cache()
-
- ############################################################################################
- # define the build timestamp
-
- if( NOT DEFINED EC_BUILD_TIMESTAMP )
- ecbuild_get_timestamp( EC_BUILD_TIMESTAMP )
- set( EC_BUILD_TIMESTAMP "${EC_BUILD_TIMESTAMP}" CACHE INTERNAL "Build timestamp" )
- endif()
-
- message( STATUS "---------------------------------------------------------" )
+ include(CheckFortranFunctionExists)
+ if( CMAKE_C_COMPILER_LOADED AND ENABLE_FORTRAN_C_INTERFACE )
+ include(FortranCInterface)
+ endif()
+ set( EC_HAVE_FORTRAN 1 )
+ endif()
+
+ include(FeatureSummary) # support features in cmake
+
+ include(TestBigEndian)
+
+ ############################################################################################
+ # backport of cmake > 2.8.4 functions
+
+ if( "${CMAKE_VERSION}" VERSION_LESS "2.8.6" )
+ include( ${CMAKE_CURRENT_LIST_DIR}/2.8/CMakePushCheckState.cmake )
+ else()
+ include(CMakePushCheckState)
+ endif()
+
+ ############################################################################################
+ # add our macros
+
+ include( ecbuild_debug_var )
+ include( ecbuild_log )
+ include( ecbuild_list_macros )
+
+ include( ecbuild_check_c_source_return )
+ include( ecbuild_check_cxx_source_return )
+ include( ecbuild_check_cxx11 )
+ include( ecbuild_check_fortran_source_return )
+
+ include( ecbuild_requires_macro_version )
+ include( ecbuild_get_date )
+ include( ecbuild_add_persistent )
+ include( ecbuild_generate_config_headers )
+ include( ecbuild_generate_rpc )
+ include( ecbuild_generate_yy )
+ include( ecbuild_echo_targets )
+ include( ecbuild_features )
+ include( ecbuild_add_option )
+ include( ecbuild_add_library )
+ include( ecbuild_add_executable )
+ include( ecbuild_append_to_rpath )
+ include( ecbuild_download_resource )
+ include( ecbuild_get_test_data )
+ include( ecbuild_add_c_flags )
+ include( ecbuild_add_cxx_flags )
+ include( ecbuild_add_cxx11_flags )
+ include( ecbuild_get_cxx11_flags )
+ include( ecbuild_add_fortran_flags )
+ include( ecbuild_add_test )
+ include( ecbuild_add_resources )
+ include( ecbuild_get_resources )
+ include( ecbuild_dont_pack )
+ include( ecbuild_project_files )
+ include( ecbuild_declare_project )
+ include( ecbuild_install_project )
+ include( ecbuild_separate_sources )
+ include( ecbuild_find_package )
+ include( ecbuild_use_package )
+ include( ecbuild_list_extra_search_paths )
+ include( ecbuild_add_extra_search_paths )
+ include( ecbuild_print_summary )
+ include( ecbuild_warn_unused_files )
+ include( ecbuild_find_mpi )
+ include( ecbuild_find_omp )
+ include( ecbuild_find_perl )
+ include( ecbuild_find_python )
+ include( ecbuild_find_lexyacc )
+ include( ecbuild_find_fortranlibs )
+ include( ecbuild_git )
+ include( ecbuild_enable_fortran )
+ include( ecbuild_bundle )
+ include( ecbuild_pkgconfig )
+ include( ecbuild_cache )
+
+ include( ${CMAKE_CURRENT_LIST_DIR}/contrib/GetGitRevisionDescription.cmake )
+
+ ############################################################################################
+ # kickstart the build system
+
+ ecbuild_prepare_cache()
+
+ include( ecbuild_define_options ) # define build options
+ include( ecbuild_check_compiler ) # check for compiler characteristics
+ include( ecbuild_check_os ) # check for os characteristics
+ include( ecbuild_check_functions ) # check for available functions
+ include( ecbuild_define_paths ) # define installation paths
+ include( ecbuild_links_target ) # define the links target
+ include( ecbuild_setup_test_framework ) # setup test framework
+ include( ecbuild_define_uninstall ) # define uninstall target
+
+ ecbuild_flush_cache()
+
+ ############################################################################################
+ # define the build timestamp
+
+ if( NOT DEFINED EC_BUILD_TIMESTAMP )
+ ecbuild_get_timestamp( EC_BUILD_TIMESTAMP )
+ set( EC_BUILD_TIMESTAMP "${EC_BUILD_TIMESTAMP}" CACHE INTERNAL "Build timestamp" )
+ endif()
+
+ message( STATUS "---------------------------------------------------------" )
endif()
diff --git a/cmake/ecbuild_uninstall.cmake.in b/cmake/ecbuild_uninstall.cmake.in
new file mode 100644
index 0000000..2037e36
--- /dev/null
+++ b/cmake/ecbuild_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+ message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+ if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+ endif(NOT "${rm_retval}" STREQUAL 0)
+ else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+ endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/cmake/ecbuild_use_package.cmake b/cmake/ecbuild_use_package.cmake
index 3d77384..dd30323 100644
--- a/cmake/ecbuild_use_package.cmake
+++ b/cmake/ecbuild_use_package.cmake
@@ -7,200 +7,280 @@
# does it submit to any jurisdiction.
##############################################################################
-# function for adding a subproject directory
+#.rst:
+#
+# ecbuild_use_package
+# ===================
+#
+# Add a project from a source directory, a subdirectory or search for it. ::
+#
+# ecbuild_use_package( PROJECT <name>
+# [ VERSION <version> [ EXACT ] ]
+# [ REQUIRED ]
+# [ QUIET ] )
+#
+# Options
+# -------
+#
+# NAME : required
+# package name (used as ``Find<name>.cmake`` and ``<name>-config.cmake``)
+#
+# VERSION : optional
+# minimum required package version
+#
+# EXACT : optional, requires VERSION
+# require the exact version rather than a minimum version
+#
+# REQUIRED : optional
+# fail if package cannot be found
+#
+# QUIET : optional
+# do not output package information if found
+#
+# Input variables
+# ---------------
+#
+# The following CMake variables influence the behaviour if set (``<name>``
+# is the package name as given, ``<NAME>`` is the capitalised version):
+#
+# :<NAME>_SOURCE: path to source directory for package
+# :SUBPROJECT_DIRS: list of additional paths to search for package source
+#
+# See also ``ecbuild_find_package`` for additional CMake variables relevant
+# when search for the package (step 6 below).
+#
+# Usage
+# -----
+#
+# Use another CMake project as a dependency by either building it from source
+# i.e. adding its source directory as a subdirectory or searching for it. This
+# transparently deals with the case where the project has already been included
+# e.g. because multiple projects with shared dependencies are built together.
+#
+# The search proceeds as follows:
+#
+# 1. If ``SUBPROJECT_DIRS`` is set, each directory in the list is searched
+# for a subdirectory <name> and ``<NAME>_SOURCE`` is set to the first one
+# found (if any).
+#
+# 2. If ``<NAME>_SOURCE`` is set, check if this directory is a CMake project
+# (contains ``CMakeLists.txt`` and fail if not.
+#
+# 3. Otherwise, check if the current directory has a ``<name>`` subdirectory.
+#
+# 4. If the project has not been previously marked as found or added as a
+# subdirectory and a project source directory has been found in steps 1-3
+# add this subdirectory.
+#
+# 5. If the project has been marked as found, check the version.
+#
+# 6. Otherwise, search for the project using ``ecbuild_find_package``.
+#
##############################################################################
macro( ecbuild_use_package )
- set( options REQUIRED QUIET EXACT )
- set( single_value_args PROJECT VERSION )
- set( multi_value_args )
+ set( options REQUIRED QUIET EXACT )
+ set( single_value_args PROJECT VERSION )
+ set( multi_value_args )
- cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
+ cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} )
- if(_p_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unknown keywords given to ecbuild_use_package(): \"${_p_UNPARSED_ARGUMENTS}\"")
- endif()
+ if(_p_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ecbuild_use_package(): \"${_p_UNPARSED_ARGUMENTS}\"")
+ endif()
- if( NOT _p_PROJECT )
- message(FATAL_ERROR "The call to ecbuild_use_package() doesn't specify the PROJECT.")
- endif()
-
- if( _p_EXACT AND NOT _p_VERSION )
- message(FATAL_ERROR "Call to ecbuild_use_package() requests EXACT but doesn't specify VERSION.")
- endif()
+ if( NOT _p_PROJECT )
+ message(FATAL_ERROR "The call to ecbuild_use_package() doesn't specify the PROJECT.")
+ endif()
- # try to find the package as a subproject and build it
+ if( _p_EXACT AND NOT _p_VERSION )
+ message(FATAL_ERROR "Call to ecbuild_use_package() requests EXACT but doesn't specify VERSION.")
+ endif()
- string( TOUPPER ${_p_PROJECT} PNAME )
+ # try to find the package as a subproject and build it
- # user defined dir with subprojects
+ string( TOUPPER ${_p_PROJECT} pkgUPPER )
- if( NOT DEFINED ${PNAME}_SOURCE AND DEFINED SUBPROJECT_DIRS )
- foreach( dir ${SUBPROJECT_DIRS} )
- if( EXISTS ${dir}/${_p_PROJECT} AND EXISTS ${dir}/${_p_PROJECT}/CMakeLists.txt )
- set( ${PNAME}_SOURCE "${dir}/${_p_PROJECT}" )
- endif()
- endforeach()
- endif()
+ # user defined dir with subprojects
- # user defined path to subproject
+ if( NOT DEFINED ${pkgUPPER}_SOURCE AND DEFINED SUBPROJECT_DIRS )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): scanning subproject directories ${SUBPROJECT_DIRS}")
+ foreach( dir ${SUBPROJECT_DIRS} )
+ if( EXISTS ${dir}/${_p_PROJECT} AND EXISTS ${dir}/${_p_PROJECT}/CMakeLists.txt )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): setting ${pkgUPPER}_SOURCE to ${dir}/${_p_PROJECT}")
+ set( ${pkgUPPER}_SOURCE "${dir}/${_p_PROJECT}" )
+ endif()
+ endforeach()
+ endif()
- if( DEFINED ${PNAME}_SOURCE )
+ # user defined path to subproject
- if( NOT EXISTS ${${PNAME}_SOURCE} OR NOT EXISTS ${${PNAME}_SOURCE}/CMakeLists.txt )
- message( FATAL_ERROR "User defined source directory '${${PNAME}_SOURCE}' for project '${_p_PROJECT}' does not exist or does not contain a CMakeLists.txt file." )
- endif()
+ if( DEFINED ${pkgUPPER}_SOURCE )
- set( ${PNAME}_subproj_dir_ "${${PNAME}_SOURCE}" )
+ if( NOT EXISTS ${${pkgUPPER}_SOURCE} OR NOT EXISTS ${${pkgUPPER}_SOURCE}/CMakeLists.txt )
+ message( FATAL_ERROR "User defined source directory '${${pkgUPPER}_SOURCE}' for project '${_p_PROJECT}' does not exist or does not contain a CMakeLists.txt file." )
+ endif()
- else() # default is 'dropped in' subdirectory named as project
+ set( ${pkgUPPER}_subproj_dir_ "${${pkgUPPER}_SOURCE}" )
- if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT} AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}/CMakeLists.txt )
- set( ${PNAME}_subproj_dir_ "${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}" )
- endif()
+ else() # default is 'dropped in' subdirectory named as project
+ if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT} AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}/CMakeLists.txt )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): found ${_p_PROJECT} in subdirectory ${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}")
+ set( ${pkgUPPER}_subproj_dir_ "${CMAKE_CURRENT_SOURCE_DIR}/${_p_PROJECT}" )
endif()
- # check if was already added as subproject ...
+ endif()
- set( _just_added 0 )
- set( _do_version_check 0 )
- set( _source_description "" )
+ # check if was already added as subproject ...
- list( FIND ECBUILD_PROJECTS ${_p_PROJECT} _ecbuild_project_${PNAME} )
+ set( _just_added 0 )
+ set( _do_version_check 0 )
+ set( _source_description "" )
- if( NOT _ecbuild_project_${PNAME} EQUAL "-1" )
- set( ${PNAME}_previous_subproj_ 1 )
- else()
- set( ${PNAME}_previous_subproj_ 0 )
- endif()
+ list( FIND ECBUILD_PROJECTS ${_p_PROJECT} _ecbuild_project_${pkgUPPER} )
- # solve capitalization issues
-
- if( ${_p_PROJECT}_FOUND AND NOT ${PNAME}_FOUND )
- set( ${PNAME}_FOUND 1 )
- endif()
- if( ${PNAME}_FOUND AND NOT ${_p_PROJECT}_FOUND )
- set( ${_p_PROJECT}_FOUND 1 )
- endif()
+ if( NOT _ecbuild_project_${pkgUPPER} EQUAL "-1" )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} was previously added as a subproject")
+ set( ${pkgUPPER}_previous_subproj_ 1 )
+ else()
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} was not previously added as a subproject")
+ set( ${pkgUPPER}_previous_subproj_ 0 )
+ endif()
+
+ # solve capitalization issues
+
+ if( ${_p_PROJECT}_FOUND AND NOT ${pkgUPPER}_FOUND )
+ set( ${pkgUPPER}_FOUND 1 )
+ endif()
+ if( ${pkgUPPER}_FOUND AND NOT ${_p_PROJECT}_FOUND )
+ set( ${_p_PROJECT}_FOUND 1 )
+ endif()
+
+ # Case 1) project was NOT previously added as subproject and is NOT already FOUND
- # Case 1) project was NOT added as subproject and is NOT FOUND
+ if( NOT ${pkgUPPER}_FOUND AND NOT ${pkgUPPER}_previous_subproj_ )
- if( NOT ${PNAME}_FOUND AND NOT ${PNAME}_previous_subproj_ )
+ # check if SUBPROJDIR is set
- # check if SUBPROJDIR is set
+ if( DEFINED ${pkgUPPER}_subproj_dir_ )
- if( DEFINED ${PNAME}_subproj_dir_ )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 1) project was NOT previously added as subproject and is NOT already FOUND")
- # check version is acceptable
- set( _just_added 1 )
- set( _do_version_check 1 )
- set( _source_description "sub-project ${_p_PROJECT} (sources)" )
+ # check version is acceptable
+ set( _just_added 1 )
+ set( _do_version_check 1 )
+ set( _source_description "sub-project ${_p_PROJECT} (sources)" )
- # add as a subproject
+ # add as a subproject
- set( ${PNAME}_subproj_dir_ ${${PNAME}_subproj_dir_} CACHE PATH "Path to ${_p_PROJECT} source directory" )
+ set( ${pkgUPPER}_subproj_dir_ ${${pkgUPPER}_subproj_dir_} CACHE PATH "Path to ${_p_PROJECT} source directory" )
- set( ECBUILD_PROJECTS ${ECBUILD_PROJECTS} ${_p_PROJECT} CACHE INTERNAL "" )
+ set( ECBUILD_PROJECTS ${ECBUILD_PROJECTS} ${_p_PROJECT} CACHE INTERNAL "" )
- add_subdirectory( ${${PNAME}_subproj_dir_} ${_p_PROJECT} )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): ${_p_PROJECT} found in subdirectory ${${pkgUPPER}_subproj_dir_}")
+ add_subdirectory( ${${pkgUPPER}_subproj_dir_} ${_p_PROJECT} )
- set( ${PNAME}_FOUND 1 )
- set( ${_p_PROJECT}_VERSION ${${PNAME}_VERSION} )
+ set( ${_p_PROJECT}_BASE_DIR ${CMAKE_BINARY_DIR} )
- endif()
+ set( ${pkgUPPER}_FOUND 1 )
+ set( ${_p_PROJECT}_VERSION ${${pkgUPPER}_VERSION} )
endif()
- # Case 2) project was already added as subproject, so is already FOUND -- BUT must check version acceptable
+ endif()
- if( ${PNAME}_previous_subproj_ )
+ # Case 2) project was already added as subproject, so is already FOUND -- BUT must check version acceptable
- if( NOT ${PNAME}_FOUND )
- message( FATAL_ERROR "${_p_PROJECT} was already included as sub-project but ${PNAME}_FOUND isn't set -- this is likely a BUG in ecbuild" )
- endif()
+ if( ${pkgUPPER}_previous_subproj_ )
- # check version is acceptable
- set( _do_version_check 1 )
- set( _source_description "already existing sub-project ${_p_PROJECT} (sources)" )
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 2) project was already added as subproject, check version is acceptable")
+ if( NOT ${pkgUPPER}_FOUND )
+ message( FATAL_ERROR "${_p_PROJECT} was already included as sub-project but ${pkgUPPER}_FOUND isn't set -- this is likely a BUG in ecbuild" )
endif()
- # Case 3) project was NOT added as subproject, but is FOUND -- so it was previously found as a binary ( either build or install tree )
+ # check version is acceptable
+ set( _do_version_check 1 )
+ set( _source_description "already existing sub-project ${_p_PROJECT} (sources)" )
- if( ${PNAME}_FOUND AND NOT ${PNAME}_previous_subproj_ AND NOT _just_added )
+ endif()
- # check version is acceptable
- set( _do_version_check 1 )
- set( _source_description "previously found package ${_p_PROJECT} (binaries)" )
+ # Case 3) project was NOT added as subproject, but is FOUND -- so it was previously found as a binary ( either build or install tree )
- endif()
+ if( ${pkgUPPER}_FOUND AND NOT ${pkgUPPER}_previous_subproj_ AND NOT _just_added )
- # test version for Cases 1,2,3
-
-# debug_var( _p_PROJECT )
-# debug_var( _p_VERSION )
-# debug_var( ${PNAME}_VERSION )
-# debug_var( ${_p_PROJECT}_VERSION )
-# debug_var( _just_added )
-# debug_var( _do_version_check )
-# debug_var( _source_description )
-# debug_var( ${PNAME}_FOUND )
-# debug_var( ${PNAME}_previous_subproj_ )
-
- if( _p_VERSION AND _do_version_check )
- if( _p_EXACT )
- if( NOT ${_p_PROJECT}_VERSION VERSION_EQUAL _p_VERSION )
- message( FATAL_ERROR "${PROJECT_NAME} requires (exactly) ${_p_PROJECT} = ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
- endif()
- else()
- if( _p_VERSION VERSION_LESS ${_p_PROJECT}_VERSION OR _p_VERSION VERSION_EQUAL ${_p_PROJECT}_VERSION )
- message( STATUS "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
- else()
- message( FATAL_ERROR "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected only ${_source_description} ${${_p_PROJECT}_VERSION}" )
- endif()
- endif()
- endif()
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 3) project was NOT previously added as subproject, but is FOUND")
- # Case 4) is NOT FOUND so far, NOT as sub-project (now or before), and NOT as binary neither
- # so try to find precompiled binaries or a build tree
+ # check version is acceptable
+ set( _do_version_check 1 )
+ set( _source_description "previously found package ${_p_PROJECT} (binaries)" )
- if( NOT ${PNAME}_FOUND )
+ endif()
- set( _opts )
- if( _p_VERSION )
- list( APPEND _opts VERSION ${_p_VERSION} )
- endif()
- if( _p_EXACT )
- list( APPEND _opts EXACT )
- endif()
- if( _p_REQUIRED )
- list( APPEND _opts REQUIRED )
- endif()
-
- ecbuild_find_package( NAME ${_p_PROJECT} ${_opts} )
+ # test version for Cases 1,2,3
- if( ${_p_PROJECT}_FOUND )
+ # debug_var( _p_PROJECT )
+ # debug_var( _p_VERSION )
+ # debug_var( ${pkgUPPER}_VERSION )
+ # debug_var( ${_p_PROJECT}_VERSION )
+ # debug_var( _just_added )
+ # debug_var( _do_version_check )
+ # debug_var( _source_description )
+ # debug_var( ${pkgUPPER}_FOUND )
+ # debug_var( ${pkgUPPER}_previous_subproj_ )
- set( ${PNAME}_FOUND ${${_p_PROJECT}_FOUND} )
+ if( _p_VERSION AND _do_version_check )
+ if( _p_EXACT )
+ if( NOT ${_p_PROJECT}_VERSION VERSION_EQUAL _p_VERSION )
+ message( FATAL_ERROR "${PROJECT_NAME} requires (exactly) ${_p_PROJECT} = ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ endif()
+ else()
+ if( _p_VERSION VERSION_LESS ${_p_PROJECT}_VERSION OR _p_VERSION VERSION_EQUAL ${_p_PROJECT}_VERSION )
+ message( STATUS "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected as ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ else()
+ message( FATAL_ERROR "${PROJECT_NAME} requires ${_p_PROJECT} >= ${_p_VERSION} -- detected only ${_source_description} ${${_p_PROJECT}_VERSION}" )
+ endif()
+ endif()
+ endif()
- message( STATUS "[${_p_PROJECT}] (${${_p_PROJECT}_VERSION})" )
+ # Case 4) is NOT FOUND so far, NOT as sub-project (now or before), and NOT as binary neither
+ # so try to find precompiled binaries or a build tree
- message( STATUS " ${PNAME}_INCLUDE_DIRS : [${${PNAME}_INCLUDE_DIRS}]" )
- if( ${PNAME}_DEFINITIONS )
- message( STATUS " ${PNAME}_DEFINITIONS : [${${PNAME}_DEFINITIONS}]" )
- endif()
- message( STATUS " ${PNAME}_LIBRARIES : [${${PNAME}_LIBRARIES}]" )
+ if( NOT ${pkgUPPER}_FOUND )
- endif()
+ ecbuild_debug("ecbuild_use_package(${_p_PROJECT}): 4) project has NOT been added as a subproject and is NOT already FOUND")
+ set( _opts )
+ if( _p_VERSION )
+ list( APPEND _opts VERSION ${_p_VERSION} )
+ endif()
+ if( _p_EXACT )
+ list( APPEND _opts EXACT )
+ endif()
+ if( _p_REQUIRED )
+ list( APPEND _opts REQUIRED )
endif()
-### for when we change this macro to a function()
-# set_parent_scope( ${PNAME}_FOUND )
-# set_parent_scope( ${_p_PROJECT}_FOUND )
-# set_parent_scope( ${PNAME}_VERSION )
-# set_parent_scope( ${_p_PROJECT}_VERSION )
+ ecbuild_find_package( NAME ${_p_PROJECT} ${_opts} )
+
+ if( ${_p_PROJECT}_FOUND )
+ set( ${pkgUPPER}_FOUND ${${_p_PROJECT}_FOUND} )
+ endif()
+
+ endif()
+
+ if( ${pkgUPPER}_FOUND )
+ list( APPEND ${PROJECT_NAME_CAPS}_TPLS ${_p_PROJECT} )
+ list( REMOVE_DUPLICATES ${PROJECT_NAME_CAPS}_TPLS )
+ endif()
+
+ ### for when we change this macro to a function()
+ # set_parent_scope( ${pkgUPPER}_FOUND )
+ # set_parent_scope( ${_p_PROJECT}_FOUND )
+ # set_parent_scope( ${pkgUPPER}_VERSION )
+ # set_parent_scope( ${_p_PROJECT}_VERSION )
+ # set_parent_scope( ${_p_PROJECT}_BINARY_DIR )
endmacro()
diff --git a/cmake/ecbuild_warn_unused_files.cmake b/cmake/ecbuild_warn_unused_files.cmake
index c3aa7d5..c33b213 100644
--- a/cmake/ecbuild_warn_unused_files.cmake
+++ b/cmake/ecbuild_warn_unused_files.cmake
@@ -6,8 +6,28 @@
# granted to it by virtue of its status as an intergovernmental organisation nor
# does it submit to any jurisdiction.
-############################################################################################
-# print warnings about unused files
+##############################################################################
+#.rst:
+#
+# ecbuild_warn_unused_files
+# =========================
+#
+# Print warnings about unused source files in the project. ::
+#
+# ecbuild_warn_unused_files()
+#
+# If the CMake variable ``CHECK_UNUSED_FILES`` is set, ecBuild will keep track
+# of any source files (.c, .cc, .cpp, .cxx) which are not part of a CMake
+# target. If set, this macro reports unused files if any have been found. This
+# is considered a fatal error unless ``UNUSED_FILES_LEVEL`` is set to a value
+# different from ``ERROR``.
+#
+# .. note ::
+#
+# Enabling ``CHECK_UNUSED_FILES`` can slow down the CMake configure time
+# considerably!
+#
+##############################################################################
macro( ecbuild_warn_unused_files )
@@ -26,15 +46,14 @@ macro( ecbuild_warn_unused_files )
endif()
# if unused files where found, put the list on the file
- list( LENGTH MARS_UNUSED_FILES MARS_LENGTH_UNUSED_FILES )
- if( MARS_LENGTH_UNUSED_FILES )
+ if( EC_UNUSED_FILES )
message( STATUS "")
message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
message( STATUS " !!!--- ${UNUSED_FILES_LEVEL} ---!!! ")
message( STATUS "")
message( STATUS " Unused source files found:")
- foreach( AFILE ${MARS_UNUSED_FILES} )
+ foreach( AFILE ${EC_UNUSED_FILES} )
message( STATUS " ${AFILE}")
file( APPEND ${UNUSED_FILE} "${AFILE}\n" )
endforeach()
diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in
index 86031db..e6d903d 100644
--- a/cmake/pkg-config.pc.in
+++ b/cmake/pkg-config.pc.in
@@ -5,10 +5,10 @@ git_tag=@PKGCONFIG_GIT_TAG@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${prefix}/lib
-includedir=${prefix}/include
-bindir=${prefix}/bin
-fmoddir=${prefix}/include
+libdir=${prefix}/@INSTALL_LIB_DIR@
+includedir=${prefix}/@INSTALL_INCLUDE_DIR@
+bindir=${prefix}/@INSTALL_BIN_DIR@
+fmoddir=${prefix}/@INSTALL_INCLUDE_DIR@
CC=@CMAKE_C_COMPILER@
CXX=@CMAKE_CXX_COMPILER@
diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in
index dbb936f..03f875b 100644
--- a/cmake/project-config.cmake.in
+++ b/cmake/project-config.cmake.in
@@ -47,9 +47,12 @@ set( @PNAME at _LIBRARIES ${@PNAME at _SELF_LIBRARIES} ${@PNAME at _TPL_LIBRARIE
set( @PNAME at _FEATURES "@CONF_FEATURES@" )
foreach( _f ${@PNAME at _FEATURES} )
- set( ${_f} 1 )
+ set( @PNAME at _HAVE_${_f} 1 )
endforeach()
+# Has this configuration been exported from a build tree?
+set( @PNAME at _IS_BUILD_DIR_EXPORT @_is_build_dir_export@ )
+
if( EXISTS ${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@ )
set( @PNAME at _IMPORT_FILE "${@PNAME at _CMAKE_DIR}/@CONF_IMPORT_FILE@" )
include( ${@PNAME at _IMPORT_FILE} )
@@ -59,9 +62,7 @@ endif()
if( NOT @PROJECT_NAME at _BINARY_DIR )
- set( IS_BUILD_DIR_EXPORT @_is_build_dir_export@ )
-
- if( IS_BUILD_DIR_EXPORT )
+ if( @PNAME at _IS_BUILD_DIR_EXPORT )
include( "@TOP_PROJECT_TARGETS_FILE@" OPTIONAL )
else()
include( "${@PNAME at _CMAKE_DIR}/@CMAKE_PROJECT_NAME at -targets.cmake" )
@@ -78,3 +79,12 @@ include( ${CMAKE_CURRENT_LIST_FILE}.tpls OPTIONAL )
set( @PNAME at _IMPORT_FILE ${CMAKE_CURRENT_LIST_FILE} )
mark_as_advanced( @PNAME at _IMPORT_FILE )
+# set @PROJECT_NAME at _BASE_DIR for final installations or build directories
+
+if( NOT @PROJECT_NAME@ )
+ if( @PNAME at _IS_BUILD_DIR_EXPORT )
+ set( @PROJECT_NAME at _BASE_DIR @CMAKE_BINARY_DIR@ )
+ else()
+ set( @PROJECT_NAME at _BASE_DIR @CMAKE_INSTALL_PREFIX@ )
+ endif()
+endif()
diff --git a/cmake/pymain.c b/cmake/pymain.c
new file mode 100644
index 0000000..823d57d
--- /dev/null
+++ b/cmake/pymain.c
@@ -0,0 +1,5 @@
+#include <Python.h>
+
+int main() {
+ return 0;
+}
diff --git a/magics-config.in b/magics-config.in
deleted file mode 100644
index b6098bc..0000000
--- a/magics-config.in
+++ /dev/null
@@ -1,323 +0,0 @@
-#!/bin/sh
-
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=@CMAKE_INSTALL_PREFIX@/bin
-libdir=@CMAKE_INSTALL_PREFIX@/lib
-includedir=@CMAKE_INSTALL_PREFIX@/include/magics
-F77="@CMAKE_Fortran_COMPILER@"
-CC="@CMAKE_C_COMPILER@"
-CXX="@CMAKE_CXX_COMPILER@"
-CXXFLAGS="@CMAKE_CXX_FLAGS@"
-AXX="@AXX@"
-SHLIB_EXT="@CMAKE_SHARED_LIBRARY_SUFFIX@"
-FFLAGS="@CMAKE_Fortran_FLAGS@"
-CPPLIBS="@CPPLIBS@"
-py_dir="@PYTHON_SITE_PACKAGES@"
-suffix=""
-
-#
-# add --print-config
-#
-#
-# test 64bit C/C++ & intel compiler
-#
-# configure.ac - deprecated string option for gcc !!!!
-#
-
-
-
-usage()
-{
- cat <<EOF
-Usage: magics-config [OPTION] ...
-
-Uses by default version @MAGICS_PACKAGE_VERSION@@MAGICS_PACKAGE_VERSION_ADDENDUM@ of Magics.
-
-Generic options
- --version output Magics version information.
- --help display this help and exit.
- --print-setup print how the environment can be set up
-
-Compilation support options
- --cxxflags print pre-processor and compiler flags for C/C++
- --libs print linking flags for C++
- --clibs print linking flags for C
- --libdir print directory where libraries are installed
- --f90static print library linking information (static)
- --f90shared print library linking information (shared)
-
- --compile compile simple Magics Fortran programs (default single precision!)
- Example: magics-config --compile=wind.f
- --compileC compile simple Magics C programs
- Example: magics-config --compileC=wind.c
- --suffix set suffix of Fortran or C code files
-
- --double include compiler option for fortran double precision
- (default single - only for interface - internally only double is used)
- --64bit include fortran option for 64 bit
-
-C/C++ flags use shared libraries if possible, otherwise static libraries are used. '--double' has
-NO effect on C/C++ programs.
-
-Install directories Magics was configured to
- --prefix[=DIR]
-
-EOF
- exit $1
-}
-
-if test -h ${prefix}; then
- name=$(readlink -q "${prefix}")
- if test -d ${name}; then
- prefix=name
- else
- prefix=$(dirname "${prefix}")
- prefix="${prefix}/${name}"
- fi
-fi
-
-if test $# -eq 0; then
- usage 1 1>&2
-fi
-
-while test $# -gt 0; do
- case "$1" in
- -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) ;;
- esac
-
- case $1 in
- --prefix=*)
- prefix=$optarg
- ;;
- --prefix)
- echo_prefix=yes
- ;;
- --version)
- echo "@MAGICS_VERSION_STR@"
- ;;
- --with-cairo)
- echo "@cairo@"
- ;;
- --with-python)
- echo "@python@"
- ;;
- --with-odb)
- echo "@odb@"
- ;;
- --with-netcdf)
- echo "@netcdf@"
- ;;
- --with-metview)
- echo "@metview@"
- ;;
- --with-qt)
- echo "@qt@"
- ;;
- --with-qtlib)
- echo "@qtlib@"
- ;;
- --with-bufr)
- echo "@bufr@"
- ;;
- --with-gd)
- echo "no"
- ;;
- --with-spot)
- echo "@spot@"
- ;;
- --help)
- usage 0
- ;;
- --print-setup)
- echo ""
- echo " For sh, ksh, dash and bash:"
- echo ""
- echo " export MAGPLUS_HOME=${prefix}"
- echo " export PATH=${prefix}/bin:\$PATH"
- echo " export LD_LIBRARY_PATH=${libdir}:\$LD_LIBRARY_PATH"
- echo " export PYTHONPATH=\"${py_dir}:\${PYTHONPATH:-/usr/lib}\""
- echo ""
- echo " You might want add these lines to your login scripts (.profile, .kshrc or .bashrc)."
- echo ""
- ;;
- --cxxflags)
- echo_cxxflags=yes
- ;;
- --libs)
- echo_libs=yes
- ;;
- --libdir)
- echo "${libdir}"
- ;;
- --ld-lib)
- echo "setup to use for lD_LIBRARY_PATH"
- ;;
- --python)
- echo "@PYTHON_SITE_PACKAGES@"
- ;;
- --clibs)
- echo_libs=yes
- echo_clibs=yes
- ;;
- --f90static)
- echo_static=yes
- echo_shared=no
- ;;
- --f90shared)
- echo_shared=yes
- echo_static=no
- ;;
- --suffix=*)
- suffix=$optarg
- ;;
- --compile=*)
- compile=yes
- f77_file=$optarg
- ;;
- --compileC=*)
- compileC=yes
- c_file=$optarg
- ;;
- --double)
- double=yes
- case "${F77}" in
- gfortran )
- FXX="-fdefault-real-8 ${FXX}"
- ;;
- g77 )
- echo ""#"NO DOUBLE FLAG in g77"
- ;;
- # Intel compiler
- # Portland pgf90
- # IBM fortran compiler
- ifc | ifort | pgf90 | pgf77 | xlf | xlf90 | xlf_r | xlf90_r )
- FXX="-r8 ${FXX}"
- ;;
- esac
- ;;
- --odb)
- odb=no
- ;;
- --64bit)
- amd64=yes
- case "${F77}" in
- ifc | ifort | gfortran )
- FXX="-m64 ${FXX}"
- ;;
- g77 )
- echo ""#"NO DOUBLE FLAG in g77"
- ;;
- # Portland pgf90
- pgf90 | pgf77 )
- FXX="-tp amd64 ${FXX}"
- ;;
- esac
-
- case "${CC}" in
- icc | icpc | gcc | g++ )
- CXX="-m64 ${CXX}"
- ;;
- pgc | pgcpp )
- CXX="-tp amd64 ${CXX}"
- ;;
- esac
- ;;
- *)
- usage 1 1>&2
- ;;
- esac
- shift
-done
-
-if test "$echo_prefix" = "yes"; then
- echo $prefix
-fi
-
-if test "$echo_cxxflags" = "yes"; then
- if test "$includedir" != "/usr/include" ; then
- my_cxxflags="-I${includedir}"
- fi
- echo "${AXX} ${my_cxxflags} @MAGICS_3RDPARTY_INCLUDE@"
-fi
-
-if test "$echo_libs" = "yes"; then
-if test -f ${libdir}/libMagPlus at CMAKE_SHARED_LIBRARY_SUFFIX@; then
- my_libs="-L${libdir} -lMagPlus"
- else
- my_libs="${libdir}/libMagPlus.a"
- fi
-
-
- my_libs="${my_libs} @MAGICS_EXTRA_LIBS@"
-
- if test "$echo_clibs" = "yes"; then
- my_libs="${my_libs} $CPPLIBS"
- fi
-
- echo "${my_libs}"
-fi
-
-if test "$double" = "yes"; then
- precision_static="${FXX} ${libdir}/libMagPlusDouble.a"
- precision_shared="${FXX} -L${libdir} -lMagPlusDouble"
-else
- precision_static="${FXX} ${libdir}/libMagPlusSingle.a"
- precision_shared="${FXX} -L${libdir} -lMagPlusSingle"
-fi
-
-
-if test "$echo_static" = "yes"; then
- if test -f ${libdir}/libMagPlus.a ; then
- static="${precision_static} ${libdir}/libMagPlus.a -L${libdir} @LDFLAGS@ @MAGICS_EXTRA_LIBS@ @MAGICS_RPATH@ $CPPLIBS"
- precision=${precision_static}
- echo ${static}
- else
- echo "magics-config: NO STATIC LIBRARY available"
- fi
-fi
-
-
-
-if test "$echo_shared" = "yes"; then
- if test -f ${libdir}/libMagPlus at CMAKE_SHARED_LIBRARY_SUFFIX@ ; then
- shared=" ${precision_shared} -L${libdir} -lMagPlus @LDFLAGS@ @MAGICS_RPATH@ $CPPLIBS"
- echo ${shared}
- precision=${precision_shared}
- else
- echo "magics-config: NO SHARED LIBRARY"
- fi
-fi
-
-if test "$echo_flibs" = "yes"; then
- echo @FLIBS@
-fi
-
-if test "$compile" = "yes"; then
- out=""
- if test "${suffix}x" = "x"; then
- suffix="f"
- fi
- name="`basename $f77_file .${suffix}`"
-
- if test ${name} != ${f77_file} ; then
- out="-o $name " ### avoid overriding source file
- fi
- echo "$F77 ${out}$f77_file ${FFLAGS} ${precision} -L${libdir} -lMagPlus @LDFLAGS@ @MAGICS_EXTRA_LIBS@ $CPPLIBS"
- $F77 ${out}$f77_file ${FFLAGS} ${precision} -L${libdir} -Wl,-rpath,${libdir} -lMagPlus @LDFLAGS@ @MAGICS_EXTRA_LIBS@ $CPPLIBS
-fi
-
-if test "$compileC" = "yes"; then
- out=""
- if test "${suffix}x" = "x"; then
- suffix="c"
- fi
-
- name="`basename $c_file .${suffix}`"
-
- if test ${name} != ${c_file} ; then
- out="-o $name " ### avoid overriding source file
- fi
- echo "$CC ${out}$c_file ${CFLAGS} -L${libdir} -lMagPlus @LDFLAGS@ @MAGICS_EXTRA_LIBS@ $CPPLIBS @FLIBS@"
- $CC ${out}$c_file ${CFLAGS} -I${includedir} -L${libdir} -Wl,-rpath,${libdir} -lMagPlus @LDFLAGS@ @MAGICS_EXTRA_LIBS@ $CPPLIBS @FLIBS@
-fi
diff --git a/magics-import.cmake.in b/magics-import.cmake.in
new file mode 100644
index 0000000..198c366
--- /dev/null
+++ b/magics-import.cmake.in
@@ -0,0 +1,5 @@
+if( @PNAME at _IS_BUILD_DIR_EXPORT )
+ set( MAGICS_METEOGRAM_SCRIPT @CMAKE_BINARY_DIR@/apps/metgram/metgram )
+else()
+ set( MAGICS_METEOGRAM_SCRIPT @CMAKE_INSTALL_PREFIX@/bin/metgram )
+endif()
diff --git a/project_summary.cmake b/project_summary.cmake
index 80e58a6..95ccab6 100644
--- a/project_summary.cmake
+++ b/project_summary.cmake
@@ -27,8 +27,8 @@ if(ODB_API_FOUND)
message( STATUS " libs : [${ODB_API_LIBRARIES}]" )
endif()
-if(EMOS_FOUND)
- message( STATUS " EMOS libs : [${EMOS_LIBRARIES}]" )
+if(LIBEMOS_FOUND)
+ message( STATUS " LIBEMOS libs : [${LIBEMOS_LIBRARIES}]" )
endif()
if(FORTRANLIBS_FOUND)
@@ -50,4 +50,4 @@ if(EXPAT_FOUND)
message( STATUS " libs : [${EXPAT_LIBRARIES}]" )
endif()
-message( STATUS " Magics extra libs : [${MAGICS_EXTRA_LIBS}]" )
+message( STATUS " Magics extra libs : [${MAGICS_EXTRA_LIBRARIES}]" )
diff --git a/python/Magics/CMakeLists.txt b/python/Magics/CMakeLists.txt
index d1d920c..858d540 100644
--- a/python/Magics/CMakeLists.txt
+++ b/python/Magics/CMakeLists.txt
@@ -1,4 +1,4 @@
-if( ENABLE_PYTHON AND NUMPY_FOUND )
+if( HAVE_PYTHON )
### python destination
@@ -9,6 +9,7 @@ if( ENABLE_PYTHON AND NUMPY_FOUND )
debug_var( relative_rpath )
+ # See comment below, where the following lines are overriden
ecbuild_append_to_rpath( ${relative_rpath} )
ecbuild_append_to_rpath( "../../lib" ) # for the ctest to find magics libs
@@ -29,10 +30,21 @@ if( ENABLE_PYTHON AND NUMPY_FOUND )
set_source_files_properties(partio.i PROPERTIES SWIG_FLAGS "-includeall")
- swig_link_libraries( Magics MagPlusShared ${PYTHON_LIBRARIES} )
+ swig_link_libraries( Magics MagPlus ${PYTHON_LIBRARIES} )
execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/Magics.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py )
-
+
+ # On the MAC, only one RPATH cat be set (Mac does not understand path:path:path)
+ # Someone, please fix
+ # set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+ set_target_properties(_Magics PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+
+ ### make it available in the build dir
+
+ file( MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${PYTHON_SITE} )
+
+ execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/${PYTHON_DEST} )
+
### install to final destination
install( TARGETS _Magics DESTINATION ${PYTHON_DEST} )
diff --git a/python/Magics/Magics_interface.cc b/python/Magics/Magics_interface.cc
index 321ad28..29d84b9 100755
--- a/python/Magics/Magics_interface.cc
+++ b/python/Magics/Magics_interface.cc
@@ -89,6 +89,9 @@ void wrepjson() {
mag_wrepjson();
}
+void geojson() {
+ mag_geojson();
+}
void epsinput() {
mag_epsinput();
diff --git a/python/Magics/macro.py b/python/Magics/macro.py
index f8becfd..535e136 100644
--- a/python/Magics/macro.py
+++ b/python/Magics/macro.py
@@ -21,6 +21,7 @@ actions={
"pcont": "pcont",
"mcont": "pcont",
"pgeo": "pgeo",
+ "mgeojson": "pgeojson",
"mgeo": "pgeo",
"mlegend": "",
"plegend": "",
@@ -402,6 +403,7 @@ minput = make_action("minput", Magics.minput, "Input+Data")
mtable = make_action("mtable", Magics.mtable, "CSV+Table+Decoder")
+mgeojson = make_action("mgeojson", Magics.geojson, "GeoJSon")
mwrepjson = make_action("mwrepjson", Magics.wrepjson, "WrepJSon")
mepsinput = make_action("mepsinput", Magics.epsinput, "EpsInput")
mepscloud = make_action("mepscloud", Magics.epscloud)
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake b/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
new file mode 100644
index 0000000..1e12d66
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-Cray.cmake
@@ -0,0 +1,81 @@
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc Cray )
+CMAKE_FORCE_CXX_COMPILER ( CC Cray )
+CMAKE_FORCE_Fortran_COMPILER ( ftn Cray )
+
+link_libraries("$ENV{CC_X86_64}/lib/x86-64/libcray-c++-rts.so")
+link_libraries("-lmpichf90_cray")
+link_libraries("-lmpichcxx_cray")
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# FLAGS COMMON TO ALL BUILD TYPES
+####################################################################
+
+set( OMP_C_FLAGS "-homp" )
+set( OMP_CXX_FLAGS "-homp" )
+set( OMP_Fortran_FLAGS "-homp" )
+
+set( OMPSTUBS_C_FLAGS "-hnoomp" )
+set( OMPSTUBS_CXX_FLAGS "-hnoomp" )
+set( OMPSTUBS_Fortran_FLAGS "-hnoomp" )
+
+set( CMAKE_C_FLAGS "" CACHE STRING "" FORCE )
+set( CMAKE_CXX_FLAGS "" CACHE STRING "" FORCE )
+set( CMAKE_Fortran_FLAGS "-emf -rmoid" CACHE STRING "" FORCE ) # -emf activates .mods and uses lower case -rmoid produces a listing file
+
+####################################################################
+# RELEASE FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+set( ECBUILD_CXX_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+set( ECBUILD_Fortran_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+
+####################################################################
+# BIT REPRODUCIBLE FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_BIT "-O1 -G2 -hflex_mp=conservative -hadd_paren -hfp1 -DNDEBUG" )
+set( ECBUILD_CXX_FLAGS_BIT "-O1 -G2 -hflex_mp=conservative -hadd_paren -hfp1 -DNDEBUG" )
+set( ECBUILD_Fortran_FLAGS_BIT "-O1 -G2 -hflex_mp=conservative -hadd_paren -hfp1 -DNDEBUG" )
+
+####################################################################
+# RELWITHDEBINFO FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+set( ECBUILD_CXX_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+set( ECBUILD_Fortran_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+
+####################################################################
+# DEBUG FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_DEBUG "-O0 -G0" )
+set( ECBUILD_CXX_FLAGS_DEBUG "-O0 -G0" )
+set( ECBUILD_Fortran_FLAGS_DEBUG "-O0 -G0" )
+
+####################################################################
+# PRODUCTION FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+set( ECBUILD_CXX_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+set( ECBUILD_Fortran_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,loadmap -Wl,--as-needed -Ktrap=fp" )
+
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake b/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake
new file mode 100644
index 0000000..3c890d5
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-GNU.cmake
@@ -0,0 +1,73 @@
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc GNU )
+CMAKE_FORCE_CXX_COMPILER ( CC GNU )
+CMAKE_FORCE_Fortran_COMPILER ( ftn GNU )
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# FLAGS COMMON TO ALL BUILD TYPES
+####################################################################
+
+set( OMP_C_FLAGS "-fopenmp" )
+set( OMP_CXX_FLAGS "-fopenmp" )
+set( OMP_Fortran_FLAGS "-fopenmp" )
+
+set( CMAKE_C_FLAGS "" CACHE STRING "" FORCE )
+set( CMAKE_CXX_FLAGS "" CACHE STRING "" FORCE )
+set( CMAKE_Fortran_FLAGS "" CACHE STRING "" FORCE )
+
+####################################################################
+# RELEASE FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+#set( ECBUILD_CXX_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+#set( ECBUILD_Fortran_FLAGS_RELEASE "-O3 -hfp3 -hscalar3 -hvector3 -DNDEBUG" )
+
+####################################################################
+# BIT REPRODUCIBLE FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG" )
+set( ECBUILD_CXX_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG" )
+set( ECBUILD_Fortran_FLAGS_BIT "-g -O2 -m64 -march=native -DNDEBUG -fno-range-check -ffree-line-length-300 -fconvert=big-endian" )
+
+####################################################################
+# RELWITHDEBINFO FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+#set( ECBUILD_CXX_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+#set( ECBUILD_Fortran_FLAGS_RELWITHDEBINFO "-O2 -hfp1 -Gfast -DNDEBUG" )
+
+####################################################################
+# DEBUG FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_DEBUG "-O0 -G0" )
+#set( ECBUILD_CXX_FLAGS_DEBUG "-O0 -G0" )
+#set( ECBUILD_Fortran_FLAGS_DEBUG "-O0 -G0" )
+
+####################################################################
+# PRODUCTION FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+#set( ECBUILD_CXX_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+#set( ECBUILD_Fortran_FLAGS_PRODUCTION "-O2 -hfp1 -G2" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+
diff --git a/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake b/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake
new file mode 100644
index 0000000..485b122
--- /dev/null
+++ b/share/ecbuild/toolchains/ecmwf-XC30-Intel.cmake
@@ -0,0 +1,76 @@
+####################################################################
+# COMPILER
+####################################################################
+
+include(CMakeForceCompiler)
+
+CMAKE_FORCE_C_COMPILER ( cc Intel )
+CMAKE_FORCE_CXX_COMPILER ( CC Intel )
+CMAKE_FORCE_Fortran_COMPILER ( ftn Intel )
+
+set( ECBUILD_FIND_MPI OFF )
+set( ECBUILD_TRUST_FLAGS ON )
+
+####################################################################
+# FLAGS COMMON TO ALL BUILD TYPES
+####################################################################
+
+set( OMP_C_FLAGS "-qopenmp -qopenmp-threadprivate=compat -qopenmp-report=2 -qopt-report-phase=vec,openmp" )
+set( OMP_CXX_FLAGS "-qopenmp -qopenmp-threadprivate=compat -qopenmp-report=2 -qopt-report-phase=vec,openmp" )
+set( OMP_Fortran_FLAGS " -openmp -openmp-threadprivate=compat -openmp-report=2 -opt-report-phase=vec,openmp" ) # -[q] is missing on purpose, ifort does not take -q as flag
+
+# for diagnostics:
+# -diag-enable=vec -diag-file -Winline
+
+set( CMAKE_C_FLAGS "-fp-speculation=strict -fp-model precise -traceback" CACHE STRING "" FORCE )
+set( CMAKE_CXX_FLAGS "-fp-speculation=strict -fp-model precise -traceback" CACHE STRING "" FORCE )
+set( CMAKE_Fortran_FLAGS "-fp-speculation=strict -fp-model precise -convert big_endian -assume byterecl -traceback -fpe0" CACHE STRING "" FORCE )
+
+####################################################################
+# RELEASE FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_RELEASE "not implemented" )
+#set( ECBUILD_CXX_FLAGS_RELEASE "not implemented" )
+#set( ECBUILD_Fortran_FLAGS_RELEASE "not implemented" )
+
+####################################################################
+# BIT REPRODUCIBLE FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500" )
+set( ECBUILD_CXX_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500" )
+set( ECBUILD_Fortran_FLAGS_BIT "-O2 -xAVX -finline-function -finline-limit=500 -align array64byte" )
+
+####################################################################
+# RELWITHDEBINFO FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_RELWITHDEBINFO "not implemented" )
+#set( ECBUILD_CXX_FLAGS_RELWITHDEBINFO "not implemented" )
+#set( ECBUILD_Fortran_FLAGS_RELWITHDEBINFO "not implemented" )
+
+####################################################################
+# DEBUG FLAGS
+####################################################################
+
+set( ECBUILD_C_FLAGS_DEBUG "-g -O0" )
+set( ECBUILD_CXX_FLAGS_DEBUG "-g -O0" )
+set( ECBUILD_Fortran_FLAGS_DEBUG "-g -O0" ) # ??? -align array64byte
+
+####################################################################
+# PRODUCTION FLAGS
+####################################################################
+
+#set( ECBUILD_C_FLAGS_PRODUCTION "not implemented" )
+#set( ECBUILD_CXX_FLAGS_PRODUCTION "not implemented" )
+#set( ECBUILD_Fortran_FLAGS_PRODUCTION "not implemented" )
+
+####################################################################
+# LINK FLAGS
+####################################################################
+
+set( ECBUILD_C_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_CXX_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+set( ECBUILD_Fortran_LINK_FLAGS "-Wl,-Map,load.map -Wl,--as-needed" )
+
diff --git a/share/magics/Fonts.dat b/share/magics/Fonts.dat
index 3ca2110..f264c6d 100644
--- a/share/magics/Fonts.dat
+++ b/share/magics/Fonts.dat
@@ -19,10 +19,10 @@ ID MAGICS(PostScript) PostScript name PostScriptFontfile TTF CSS (SV
14 times_bold Times-Bold n021004l.pfb timesbd.ttf Times
15 times_bolditalic Times-BoldItalic n021024l.pfb timesbi.ttf Times
16 symbol_normal Symbol s050000l.pfb symbol.ttf Symbol
-50 sansserif_normal Helvetica n019003l.pfb DejaVuSans.ttf Helvetica
-51 sansserif_italic Helvetica-Oblique n019023l.pfb DejaVuSans-Oblique.ttf Helvetica
-52 sansserif_bold Helvetica-Bold n019004l.pfb DejaVuSans-Bold.ttf Helvetica
-53 sansserif_bolditalic Helvetica-BoldOblique n019024l.pfb DejaVuSans-BoldOblique.ttf Helvetica
+50 sansserif_normal Helvetica n019003l.pfb arial.ttf Helvetica
+51 sansserif_italic Helvetica-Oblique n019023l.pfb ariali.ttf Helvetica
+52 sansserif_bold Helvetica-Bold n019004l.pfb arialbd.ttf Helvetica
+53 sansserif_bolditalic Helvetica-BoldOblique n019024l.pfb arialbi.ttf Helvetica
54 serif_normal Times-Roman n021003l.pfb DejaVuSerif.ttf Times
55 serif_italic Times-Italic n021023l.pfb DejaVuSerif-Oblique.ttf Times
56 serif_bold Times-Bold n021004l.pfb DejaVuSerif-Bold.ttf Times
diff --git a/share/magics/obs.xml b/share/magics/obs.xml
index e2ef96b..fb62f5a 100644
--- a/share/magics/obs.xml
+++ b/share/magics/obs.xml
@@ -38,7 +38,7 @@
<obs_template type='dribu_surface' rows='3' columns='3'>
- <obs_cloud_wind/>
+ <obs_station_triangle/>
<obs_temperature row='1' column='-1'/>
<obs_pressure row='1' column='1'/>
<obs_pressure_tendency row='0' column='1'/>
diff --git a/share/magics/symbols.svg b/share/magics/symbols.svg
index de0445e..ee6a759 100644
--- a/share/magics/symbols.svg
+++ b/share/magics/symbols.svg
@@ -1,529 +1,589 @@
<?xml version='1.0' standalone='no'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
-
<svg width='100%' height='100%' version='1.1' xmlns='http://www.w3.org/2000/svg'>
- <g id='unknown'>
- <polyline points='-0.3,0.4 0.3,0.4 0.3,0.1 -0.3,0.1 -0.3,-0.2 0.3,-0.2' fill='none'/>
- <circle cx='0' cy='-0.4' r='0.1' fill='8'/>
- </g>
- <g id='box'>
- <polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
- </g>
- <g id='circle'>
- <circle cx='0' cy='0' r='0.5' fill='0'/>
- </g>
- <g id='snowflake'>
- <snowflake cx='0' cy='0' r='0.3'/>
- </g>
- <g id='plus'>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
- <polyline points='0,-0.5 0,0.5' fill='none'/>
- </g>
+<g id='unknown'>
+ <polyline points='-0.3,0.4 0.3,0.4 0.3,0.1 -0.3,0.1 -0.3,-0.2 0.3,-0.2' fill='none'/>
+ <circle cx='0' cy='-0.4' r='0.1' fill='8'/>
+</g>
+
+<g id='box'>
+ <polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
+</g>
+<g id='circle'>
+ <circle cx='0' cy='0' r='0.5' fill='0'/>
+</g>
+<g id='snowflake'>
+ <snowflake cx='0' cy='0' r='0.3'/>
+</g>
+<g id='plus'>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
+ <polyline points='0,-0.5 0,0.5' fill='none'/>
+</g>
- <g id='magics_0'>
- <polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_1'>
- <circle cx='0' cy='0' r='0.5' fill='0'/>
- </g>
- <g id='magics_2'>
- <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_3'>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
+<g id='magics_0'>
+ <polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
+</g>
+<g id='magics_1'>
+ <circle cx='0' cy='0' r='0.5' fill='0'/>
+</g>
+<g id='magics_2'>
+<polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='none'/>
+</g>
+<g id='triangle'>
+<polyline points='-0.25,-0.25 0.25,-0.25 0,0.25 -0.25,-0.25' fill='none'/>
+</g>
+<g id='magics_3'>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
<polyline points='0,-0.5 0,0.5' fill='none'/>
- </g>
- <g id='magics_4'>
- <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
+</g>
+<g id='magics_4'>
+ <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
<polyline points='-0.5,0.5 0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_5'>
- <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='none'/>
- </g>
- <g id='magics_6'>
- <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='none'/>
- </g>
- <g id='magics_7'>
+</g>
+<g id='magics_5'>
+ <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='none'/>
+</g>
+<g id='magics_6'>
+ <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='none'/>
+</g>
+<g id='magics_7'>
<polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
- <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
+ <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
<polyline points='-0.5,0.5 0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_8'>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
- <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
+</g>
+<g id='magics_8'>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
+ <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
<polyline points='-0.5,0.5 0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_9'>
- <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='none'/>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
+</g>
+<g id='magics_9'>
+ <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='none'/>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
<polyline points='0,-0.5 0,0.5' fill='none'/>
- </g>
- <g id='magics_10'>
- <circle cx='0' cy='0' r='0.5' fill='0'/>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
+</g>
+<g id='magics_10'>
+ <circle cx='0' cy='0' r='0.5' fill='0'/>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
<polyline points='0,-0.5 0,0.5' fill='none'/>
- </g>
- <g id='magics_11'>
- <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='none'/>
- <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='none'/>
- </g>
- <g id='magics_12'>
+</g>
+<g id='magics_11'>
+ <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='none'/>
+ <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='none'/>
+</g>
+<g id='magics_12'>
<polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
- <polyline points='-0.5,0 0.5,0' fill='none'/>
+ <polyline points='-0.5,0 0.5,0' fill='none'/>
<polyline points='0,-0.5 0,0.5' fill='none'/>
- </g>
- <g id='magics_13'>
- <circle cx='0' cy='0' r='0.5' fill='0'/>
- <polyline points='-0.35,-0.35 0.35,0.35' fill='none'/>
- <polyline points='-0.35,0.35 0.35,-0.35' fill='none'/>
- </g>
- <g id='magics_14'>
+</g>
+<g id='magics_13'>
+ <circle cx='0' cy='0' r='0.5' fill='0'/>
+ <polyline points='-0.35,-0.35 0.35,0.35' fill='none'/>
+ <polyline points='-0.35,0.35 0.35,-0.35' fill='none'/>
+</g>
+<g id='magics_14'>
<polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='none'/>
<polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='none'/>
- </g>
- <g id='magics_15'>
- <circle cx='0' cy='0' r='0.5' fill='8'/>
- </g>
- <g id='magics_16'>
- <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='black'/>
- <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='black'/>
- </g>
- <g id='magics_17'>
- <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='black'/>
- </g>
- <g id='magics_18'>
+</g>
+<g id='magics_15'>
+ <circle cx='0' cy='0' r='0.5' fill='8'/>
+</g>
+<g id='magics_16'>
+ <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='black'/>
+ <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='black'/>
+</g>
+<g id='magics_17'>
+ <polyline points='0,-0.5 0.5,0, 0,0.5 -0.5,0 0,-0.5' fill='black'/>
+</g>
+<g id='magics_18'>
<polyline points='-0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5' fill='black'/>
- </g>
- <g id='magics_19'>
- <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='black'/>
- </g>
- <g id='magics_20'>
- <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='black'/>
- </g>
- <g id='magics_21'>
- <circle cx='0' cy='0' r='0.5' fill='1'/>
- </g>
- <g id='magics_22'>
- <circle cx='0' cy='0' r='0.5' fill='2'/>
- </g>
- <g id='magics_23'>
- <circle cx='0' cy='0' r='0.5' fill='3'/>
- </g>
- <g id='magics_24'>
+</g>
+<g id='magics_19'>
+ <polyline points='-0.5,-0.5 0.5,-0.5 0,0.5 -0.5,-0.5' fill='black'/>
+</g>
+<g id='magics_20'>
+ <polyline points='-0.5,0.5 0.5,0.5 0,-0.5 -0.5,0.5' fill='black'/>
+</g>
+<g id='magics_21'>
+ <circle cx='0' cy='0' r='0.5' fill='1'/>
+</g>
+<g id='magics_22'>
+ <circle cx='0' cy='0' r='0.5' fill='2'/>
+</g>
+<g id='magics_23'>
+ <circle cx='0' cy='0' r='0.5' fill='3'/>
+</g>
+<g id='magics_24'>
<circle cx='0' cy='0' r='0.5' fill='4'/>
- </g>
- <g id='magics_25'>
+</g>
+<g id='magics_25'>
<circle cx='0' cy='0' r='0.5' fill='5'/>
- </g>
- <g id='magics_26'>
+</g>
+<g id='magics_26'>
<circle cx='0' cy='0' r='0.5' fill='6'/>
- </g>
- <g id='magics_27'>
+</g>
+<g id='magics_27'>
<circle cx='0' cy='0' r='0.5' fill='7'/>
- </g>
- <g id='magics_28'>
+</g>
+<g id='magics_28'>
<circle cx='0' cy='0' r='0.5' fill='8'/>
- </g>
+ </g>
- <g id='ww_00'>
- </g>
- <g id='ww_01'>
- </g>
- <g id='ww_02'>
- </g>
- <g id='ww_03'>
- </g>
- <g id='ww_04'>
+<g id='ww_00_old'>
+ <circle cx='0' cy='0' r='0.35' fill='0'/>
+</g>
+<g id='ww_01_old'>
+ <circle cx='0' cy='0' r='0.35' fill='0'/>
+ <polyline points='0.,-0.35 0.,-0.55' fill='none'/>
+</g>
+<g id='ww_02_old'>
+ <circle cx='0' cy='0' r='0.35' fill='0'/>
+ <polyline points='-0.55,0. -0.35,0.' fill='none'/>
+ <polyline points='0.55,0. 0.35,0.' fill='none'/>
+</g>
+<g id='ww_03_old'>
+ <circle cx='0' cy='0' r='0.35' fill='0'/>
+ <polyline points='0.,0.35 0.,0.55' fill='none'/>
+</g>
+<g id='ww_00'>
+</g>
+<g id='ww_01'>
+</g>
+<g id='ww_02'>
+</g>
+<g id='ww_03'>
+</g>
+<g id='ww_04'>
<polyline points='-0.3,-0.3 -0.3,0.2 -0.2,0.3 -0.1,0.2 0,0.3 0.1,0.2 0.2,0.3' fill='none'/>
- </g>
- <g id='ww_05'>
+</g>
+<g id='ww_05'>
<polyline points='-0.2,-0.2 0.2,0.2 0.35,0.25 0.4,0.21 0.5,0.1 0.5,-0.1 0.4,-0.21 0.35,-0.25 0.2,-0.2 -0.2,0.2 -0.35,0.25 -0.4,0.21 -0.5,0.1 -0.5,-0.1 -0.4,-0.21 -0.35,-0.25 -0.2,-0.2' fill='none'/>
- </g>
- <g id='ww_06'>
+</g>
+<g id='ww_06'>
<polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- </g>
- <g id='ww_07'>
+</g>
+<g id='ww_07'>
<polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
<polyline points='0.,0.45 0.,-0.45' fill='none'/>
- </g>
-
-
- <g id='ww_09'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_08'>
+ <polyline points='
+ 0.25,0.34 0.2,0.36 0.1,0.38 0.,0.4 -0.1,0.38 -0.2,0.36 -0.25,0.30 -0.3,0.25
+ -.2,0.2 -.1,0.12 0.,0.09 0.1,0.12 0.25,0.2 0.1,0.25 0.,0.27 -0.1,0.25 -.2,0.2 -.3,0
+ ' fill='none'/>
+ <polyline points='
+ 0.25,-0.34 0.2,-0.36 0.1,-0.38 0.,-0.4 -0.1,-0.38 -0.2,-0.36 -0.25,-0.30 -0.3,-0.25
+ -.2,-0.2 -.1,-0.12 0.,-0.09 0.1,-0.12 0.25,-0.2 0.1,-0.25 0.,-0.27 -0.1,-0.25 -.2,-0.2 -.3,0
+ ' fill='none'/>
+</g>
+<g id='ww_09'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
<polyline points='0.39,0.45 0.42,0.35 0.46,0.1 0.46,-0.1 0.42,-0.35 0.39,-0.45' fill='none'/>
<polyline points='-0.39,0.45 -0.42,0.35 -0.46,0.1 -0.46,-0.1 -0.42,-0.35 -0.39,-0.45' fill='none'/>
- </g>
- <g id='ww_10'>
- <polyline points='-0.4,0.15 0.4,0.15' fill='none'/>
- <polyline points='-0.4,-0.15 0.4,-0.15' fill='none'/>
- </g>
- <g id='ww_11'>
- <polyline points='-0.4,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.4,0.3' fill='none'/>
- <polyline points='-0.4,0 -0.1,0' fill='none'/>
- <polyline points='0.1,0 0.4,0' fill='none'/>
- <polyline points='-0.4,-0.3 -0.1,-0.3' fill='none'/>
- <polyline points='0.1,-0.3 0.4,-0.3' fill='none'/>
- </g>
- <g id='ww_12'>
- <polyline points='-0.4,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.4,0.3' fill='none'/>
- <polyline points='-0.4,0 -0.1,0' fill='none'/>
- <polyline points='0.1,0 0.4,0' fill='none'/>
- <polyline points='-0.4,-0.3 0.4,-0.3' fill='none'/>
- </g>
- <g id='ww_13'>
- <polyline points='0.3,0.4 -0.3,0 0.3,-0.4' fill='none'/>
- <polyline points='0.2,-0.2 0.3,-0.4 0.1,-0.4' fill='none'/>
- </g>
- <g id='ww_14'>
- <circle cx='0' cy='0' r='0.1' fill='8'/>
+</g>
+<g id='ww_10'>
+ <polyline points='-0.4,0.15 0.4,0.15' fill='none'/>
+ <polyline points='-0.4,-0.15 0.4,-0.15' fill='none'/>
+</g>
+<g id='ww_11'>
+ <polyline points='-0.4,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.4,0.3' fill='none'/>
+ <polyline points='-0.4,0 -0.1,0' fill='none'/>
+ <polyline points='0.1,0 0.4,0' fill='none'/>
+ <polyline points='-0.4,-0.3 -0.1,-0.3' fill='none'/>
+ <polyline points='0.1,-0.3 0.4,-0.3' fill='none'/>
+</g>
+<g id='ww_12'>
+ <polyline points='-0.4,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.4,0.3' fill='none'/>
+ <polyline points='-0.4,0 -0.1,0' fill='none'/>
+ <polyline points='0.1,0 0.4,0' fill='none'/>
+ <polyline points='-0.4,-0.3 0.4,-0.3' fill='none'/>
+</g>
+<g id='ww_13'>
+ <polyline points='0.3,0.4 -0.3,0 0.3,-0.4' fill='none'/>
+ <polyline points='0.2,-0.2 0.3,-0.4 0.1,-0.4' fill='none'/>
+</g>
+<g id='ww_14'>
+ <circle cx='0' cy='0' r='0.1' fill='8'/>
<polyline points='0.4,-0.17 0.35,-0.25 -0.35,-0.25 -0.4,-0.17' fill='none'/>
- </g>
- <g id='ww_15'>
- <circle cx='0' cy='0' r='0.1' fill='8'/>
- <polyline points='0.33,0.4 0.25,0.35 0.25,-0.35 0.33,-0.4' fill='none'/>
- <polyline points='-0.33,0.4 -0.25,0.35 -0.25,-0.35 -0.33,-0.4' fill='none'/>
- </g>
- <g id='ww_16'>
- <circle cx='0' cy='0' r='0.1' fill='8'/>
- <polyline points='0.17,0.4 0.25,0.35 0.25,-0.35 0.17,-0.4' fill='none'/>
- <polyline points='-0.17,0.4 -0.25,0.35 -0.25,-0.35 -0.17,-0.4' fill='none'/>
- </g>
- <g id='ww_17'>
+</g>
+<g id='ww_15'>
+ <circle cx='0' cy='0' r='0.1' fill='8'/>
+ <polyline points='0.33,0.4 0.25,0.35 0.25,-0.35 0.33,-0.4' fill='none'/>
+ <polyline points='-0.33,0.4 -0.25,0.35 -0.25,-0.35 -0.33,-0.4' fill='none'/>
+</g>
+<g id='ww_16'>
+ <circle cx='0' cy='0' r='0.1' fill='8'/>
+ <polyline points='0.17,0.4 0.25,0.35 0.25,-0.35 0.17,-0.4' fill='none'/>
+ <polyline points='-0.17,0.4 -0.25,0.35 -0.25,-0.35 -0.17,-0.4' fill='none'/>
+</g>
+<g id='ww_17'>
<lightning cx='0' cy='0.0' r='0.8'/>
- </g>
- <g id='ww_18'>
- <polyline points='0,0.1 0.2,0.2 0,-0.3 -0.2,0.2 0,0.1' fill='none'/>
- </g>
- <g id='ww_19'>
- <polyline points='-0.2,0.4 -0.1,0.3 -0.1,-0.3 -0.2,-0.4' fill='none'/>
- <polyline points='0.2,0.4 0.1,0.3 0.1,-0.3 0.2,-0.4' fill='none'/>
- </g>
- <g id='ww_20'>
- <drizzle cx='0' cy='0' r='0.2'/>
+</g>
+<g id='ww_18'>
+ <polyline points='0,0.1 0.2,0.2 0,-0.3 -0.2,0.2 0,0.1' fill='none'/>
+</g>
+<g id='ww_19'>
+ <polyline points='-0.2,0.4 -0.1,0.3 -0.1,-0.3 -0.2,-0.4' fill='none'/>
+ <polyline points='0.2,0.4 0.1,0.3 0.1,-0.3 0.2,-0.4' fill='none'/>
+</g>
+<g id='ww_20'>
+ <drizzle cx='0' cy='0' r='0.2'/>
<polyline points='0,0.45 0.3,0.45 0.3,-0.45 0,-0.45' fill='none'/>
- </g>
- <g id='ww_21'>
- <circle cx='0' cy='0' r='0.2' fill='8'/>
+</g>
+<g id='ww_21'>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
<polyline points='0,0.45 0.3,0.45 0.3,-0.45 0,-0.45' fill='none'/>
- </g>
- <g id='ww_22'>
- <snowflake cx='0' cy='0' r='0.2'/>
+</g>
+<g id='ww_22'>
+ <snowflake cx='0' cy='0' r='0.2'/>
<polyline points='0,0.45 0.3,0.45 0.3,-0.45 0,-0.45' fill='none'/>
- </g>
- <g id='ww_23'>
- <circle cx='0' cy='0.25' r='0.2' fill='8'/>
- <snowflake cx='0' cy='-0.25' r='0.2'/>
+</g>
+<g id='ww_23'>
+ <circle cx='0' cy='0.24' r='0.15' fill='8'/>
+ <snowflake cx='0' cy='-0.24' r='0.2'/>
<polyline points='0,0.5 0.3,0.5 0.3,-0.5 0,-0.5' fill='none'/>
- </g>
- <g id='ww_24'>
- <polyline points='0.15,0.5 0.45,0.5 0.45,-0.5 0.15,-0.5' fill='none'/>
- <polyline points='-0.3,-0.1 -0.35,0.05 -0.32,0.1 -0.25,0.15 -0.18,0.15 -0.13,0.1 0.13,-0.11 0.13,-0.11 0.18,-0.15 0.25,-0.15 0.32,-0.1 0.35,-0.05 0.3,0.1' fill='none'/>
- </g>
+</g>
+<g id='ww_24'>
+ <polyline points='0.15,0.5 0.45,0.5 0.45,-0.5 0.15,-0.5' fill='none'/>
+ <polyline points='-0.3,-0.1 -0.35,0.05 -0.32,0.1 -0.25,0.15 -0.18,0.15 -0.13,0.1 0.13,-0.11 0.13,-0.11 0.18,-0.15 0.25,-0.15 0.32,-0.1 0.35,-0.05 0.3,0.1' fill='none'/>
+</g>
<g id='ww_25'>
<polyline points='0.15,0.5 0.45,0.5 0.45,-0.5 0.15,-0.5' fill='none'/>
- <circle cx='0' cy='0.3' r='0.2' fill='8'/>
- <triangle cx='0' cy='-0.3' r='-0.3' fill='0'/>
+ <circle cx='0' cy='0.25' r='0.15' fill='8'/>
+ <triangle cx='0' cy='-0.25' r='-0.3' fill='0'/>
</g>
<g id='ww_26'>
<polyline points='0.15,0.5 0.45,0.5 0.45,-0.5 0.15,-0.5' fill='none'/>
- <snowflake cx='0' cy='0.3' r='0.2'/>
- <triangle cx='0' cy='-0.3' r='-0.3' fill='0'/>
+ <snowflake cx='0' cy='0.25' r='0.2'/>
+ <triangle cx='0' cy='-0.25' r='-0.3' fill='0'/>
</g>
<g id='ww_27'>
<polyline points='0.15,0.5 0.45,0.5 0.45,-0.5 0.15,-0.5' fill='none'/>
- <triangle cx='0' cy='0.25' r='0.25' fill='0'/>
- <triangle cx='0' cy='-0.3' r='-0.3' fill='0'/>
+ <triangle cx='0' cy='0.22' r='0.25' fill='0'/>
+ <triangle cx='0' cy='-0.22' r='-0.3' fill='0'/>
</g>
<g id='ww_28'>
- <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
</g>
<g id='ww_29'>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
- <lightning cx='0' cy='0' r='0.6'/>
-</g>
- <g id='ww_30'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <lightning cx='0' cy='0' r='0.6'/>
+</g>
+<g id='ww_30'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
<polyline points='0.46,0.45 0.46,-0.45' fill='none'/>
- </g>
- <g id='ww_31'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- </g>
- <g id='ww_32'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_31'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0
+ 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_32'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
<polyline points='-0.46,0.45 -0.46,-0.45' fill='none'/>
- </g>
- <g id='ww_33'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
- <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_33'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
+ <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
<polyline points='0.46,0.45 0.46,-0.45' fill='none'/>
- </g>
- <g id='ww_34'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
- <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- </g>
- <g id='ww_35'>
- <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
- <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
- <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_34'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
+ <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+</g>
+<g id='ww_35'>
+ <polyline points='0.2,0.30 0.1,0.38 0,0.4 -0.1,0.38 -0.2,0.27 -0.2,0.20 -0.16,0.14 0,0 0.16,-0.14 0.2,-0.20 0.2,-0.27 0.1,-0.38 0,-0.4 -0.1,-0.38 -0.2,-0.30' fill='none'/>
+ <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
+ <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
<polyline points='-0.46,0.45 -0.46,-0.45' fill='none'/>
- </g>
- <g id='ww_36'>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- <polyline points='0,-0.4 0,0.38' fill='none'/>
- <polyline points='0,-0.4 -0.13,-0.22' fill='none'/>
- <polyline points='0,-0.4 0.13,-0.22' fill='none'/>
- </g>
- <g id='ww_37'>
- <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
- <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- <polyline points='0,-0.4 0,0.38' fill='none'/>
- <polyline points='0,-0.4 -0.13,-0.22' fill='none'/>
- <polyline points='0,-0.4 0.13,-0.22' fill='none'/>
- </g>
- <g id='ww_38'>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- <polyline points='0,0.4 0,-0.38' fill='none'/>
- <polyline points='0,0.4 -0.13,0.22' fill='none'/>
- <polyline points='0,0.4 0.13,0.22' fill='none'/>
- </g>
- <g id='ww_39'>
- <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
- <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- <polyline points='0,0.4 0,-0.38' fill='none'/>
- <polyline points='0,0.4 -0.13,0.22' fill='none'/>
- <polyline points='0,0.4 0.13,0.22' fill='none'/>
- </g>
- <g id='ww_40'>
- <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_36'>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0,-0.4 0,0.38' fill='none'/>
+ <polyline points='0,-0.4 -0.13,-0.22' fill='none'/>
+ <polyline points='0,-0.4 0.13,-0.22' fill='none'/>
+</g>
+<g id='ww_37'>
+ <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
+ <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0,-0.4 0,0.38' fill='none'/>
+ <polyline points='0,-0.4 -0.13,-0.22' fill='none'/>
+ <polyline points='0,-0.4 0.13,-0.22' fill='none'/>
+</g>
+<g id='ww_38'>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0,0.4 0,-0.38' fill='none'/>
+ <polyline points='0,0.4 -0.13,0.22' fill='none'/>
+ <polyline points='0,0.4 0.13,0.22' fill='none'/>
+</g>
+<g id='ww_39'>
+ <polyline points='-0.38,0.05 0.34,0.05' fill='none'/>
+ <polyline points='-0.38,-0.05 0.34,-0.05' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0,0.4 0,-0.38' fill='none'/>
+ <polyline points='0,0.4 -0.13,0.22' fill='none'/>
+ <polyline points='0,0.4 0.13,0.22' fill='none'/>
+</g>
+<g id='ww_40'>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
<polyline points='0.39,0.45 0.42,0.35 0.46,0.1 0.46,-0.1 0.42,-0.35 0.39,-0.45' fill='none'/>
<polyline points='-0.39,0.45 -0.42,0.35 -0.46,0.1 -0.46,-0.1 -0.42,-0.35 -0.39,-0.45' fill='none'/>
- </g>
- <g id='ww_41'>
- <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 -0.1,-0.3' fill='none'/>
- <polyline points='0.1,-0.3 0.35,-0.3' fill='none'/>
- </g>
- <g id='ww_42'>
- <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- <polyline points='0.5,-0.35 0.5,0.35' fill='none'/>
- </g>
- <g id='ww_43'>
- <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- <polyline points='0.5,-0.35 0.5,0.35' fill='none'/>
- </g>
- <g id='ww_44'>
- <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- </g>
- <g id='ww_45'>
- <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- </g>
- <g id='ww_46'>
- <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
- <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- <polyline points='-0.5,-0.35 -0.5,0.35' fill='none'/>
- </g>
- <g id='ww_47'>
- <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
- <polyline points='-0.35,0 0.35,0' fill='none'/>
- <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
- <polyline points='-0.5,-0.35 -0.5,0.35' fill='none'/>
- </g>
-
- <g id='ww_50'>
- <drizzle cx='0' cy='0' r='0.2'/>
- </g>
- <g id='ww_51'>
- <drizzle cx='-0.3' cy='0' r='0.3'/>
- <drizzle cx='0.3' cy='0' r='0.3'/>
- </g>
- <g id='ww_52'>
- <drizzle cx='0' cy='-0.3' r='0.3'/>
- <drizzle cx='0' cy='0.3' r='0.3'/>
- </g>
- <g id='ww_53'>
- <drizzle cx='0' cy='0.3' r='0.3'/>
- <drizzle cx='-0.3' cy='-0.3' r='0.3'/>
- <drizzle cx='0.3' cy='-0.3' r='0.3'/>
- </g>
- <g id='ww_54'>
- <drizzle cx='0' cy='0.45' r='0.3'/>
- <drizzle cx='0' cy='0' r='0.3'/>
- <drizzle cx='0' cy='-0.45' r='0.3'/>
- </g>
- <g id='ww_55'>
- <drizzle cx='-0.3' cy='0' r='0.3'/>
- <drizzle cx='0.3' cy='0' r='0.3'/>
- <drizzle cx='0' cy='0.45' r='0.3'/>
- <drizzle cx='0' cy='-0.45' r='0.3'/>
- </g>
-
- <g id='ww_58'>
- <circle cx='0' cy='0.3' r='0.15' fill='8'/>
- <drizzle cx='0' cy='-0.3' r='0.3'/>
- </g>
- <g id='ww_59'>
- <drizzle cx='0' cy='0.45' r='0.3'/>
- <circle cx='0' cy='0' r='0.15' fill='8'/>
- <drizzle cx='0' cy='-0.45' r='0.3'/>
- </g>
- <g id='ww_60'>
- <circle cx='0' cy='0' r='0.15' fill='8'/>
- </g>
- <g id='ww_61'>
- <circle cx='-0.3' cy='0' r='0.15' fill='8'/>
- <circle cx='0.3' cy='0' r='0.15' fill='8'/>
- </g>
- <g id='ww_62'>
- <circle cx='0' cy='0.3' r='0.15' fill='8'/>
- <circle cx='0' cy='-0.3' r='0.15' fill='8'/>
- </g>
- <g id='ww_63'>
- <circle cx='0' cy='0.3' r='0.15' fill='8'/>
- <circle cx='-0.3' cy='-0.3' r='0.15' fill='8'/>
- <circle cx='0.3' cy='-0.3' r='0.15' fill='8'/>
- </g>
- <g id='ww_64'>
- <circle cx='0' cy='0.45' r='0.15' fill='8'/>
- <circle cx='0' cy='0' r='0.15' fill='8'/>
- <circle cx='0' cy='-0.45' r='0.15' fill='8'/>
- </g>
- <g id='ww_65'>
- <circle cx='-0.3' cy='0' r='0.15' fill='8'/>
- <circle cx='0.3' cy='0' r='0.15' fill='8'/>
+</g>
+<g id='ww_41'>
+ <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 -0.1,-0.3' fill='none'/>
+ <polyline points='0.1,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_42'>
+ <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+ <polyline points='0.5,-0.35 0.5,0.35' fill='none'/>
+</g>
+<g id='ww_43'>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+ <polyline points='0.5,-0.35 0.5,0.35' fill='none'/>
+</g>
+<g id='ww_44'>
+ <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_45'>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_46'>
+ <polyline points='-0.35,0.3 -0.1,0.3' fill='none'/>
+ <polyline points='0.1,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+ <polyline points='-0.5,-0.35 -0.5,0.35' fill='none'/>
+</g>
+<g id='ww_47'>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+ <polyline points='-0.5,-0.35 -0.5,0.35' fill='none'/>
+</g>
+<g id='ww_48'>
+ <polyline points='-0.1,0. 0,-0.3 0.1,0.' fill='8'/>
+ <polyline points='-0.35,0.3 -0.15,0.3 0,-0.3 0.15,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_49'>
+ <polyline points='-0.35,0.3 0.35,0.3' fill='none'/>
+ <polyline points='-0.1,0. 0,-0.3 0.1,0.' fill='8'/>
+ <polyline points='-0.15,0.3 0,-0.3 0.15,0.3' fill='none'/>
+ <polyline points='-0.35,0 0.35,0' fill='none'/>
+ <polyline points='-0.35,-0.3 0.35,-0.3' fill='none'/>
+</g>
+<g id='ww_50'>
+ <drizzle cx='0' cy='0' r='0.25'/>
+</g>
+<g id='ww_51'>
+ <drizzle cx='-0.3' cy='0' r='0.25'/>
+ <drizzle cx='0.3' cy='0' r='0.25'/>
+</g>
+<g id='ww_52'>
+ <drizzle cx='0' cy='-0.3' r='0.25'/>
+ <drizzle cx='0' cy='0.3' r='0.25'/>
+</g>
+<g id='ww_53'>
+ <drizzle cx='0' cy='0.3' r='0.25'/>
+ <drizzle cx='-0.3' cy='-0.3' r='0.25'/>
+ <drizzle cx='0.3' cy='-0.3' r='0.25'/>
+</g>
+<g id='ww_54'>
+ <drizzle cx='0' cy='0.45' r='0.25'/>
+ <drizzle cx='0' cy='0' r='0.25'/>
+ <drizzle cx='0' cy='-0.45' r='0.25'/>
+</g>
+<g id='ww_55'>
+ <drizzle cx='-0.3' cy='0' r='0.25'/>
+ <drizzle cx='0.3' cy='0' r='0.25'/>
+ <drizzle cx='0' cy='0.45' r='0.25'/>
+ <drizzle cx='0' cy='-0.45' r='0.25'/>
+</g>
+<g id='ww_56'>
+ <polyline points='-0.35,-0.1 -0.4,0.05 -0.37,0.1 -0.30,0.15 -0.23,0.15 -0.18,0.1
+ 0.18,-0.1 0.23,-0.15 0.3,-0.15 0.37,-0.1 0.4,-0.05 0.35,0.1' fill='none'/>
+ <drizzle cx='-0.18' cy='-0.2' r='0.2'/>
+</g>
+<g id='ww_57'>
+ <polyline points='-0.35,-0.1 -0.4,0.05 -0.37,0.1 -0.30,0.15 -0.23,0.15 -0.18,0.1
+ 0.18,-0.1 0.23,-0.15 0.3,-0.15 0.37,-0.1 0.4,-0.05 0.35,0.1' fill='none'/>
+ <drizzle cx='-0.18' cy='-0.2' r='0.2'/>
+ <drizzle cx='0.18' cy='0.2' r='0.2'/>
+</g>
+<g id='ww_58'>
+ <circle cx='0' cy='0.3' r='0.15' fill='8'/>
+ <drizzle cx='0' cy='-0.3' r='0.25'/>
+</g>
+<g id='ww_59'>
+ <drizzle cx='0' cy='0.45' r='0.25'/>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
+ <drizzle cx='0' cy='-0.45' r='0.25'/>
+</g>
+<g id='ww_60'>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
+</g>
+<g id='ww_61'>
+ <circle cx='-0.3' cy='0' r='0.15' fill='8'/>
+ <circle cx='0.3' cy='0' r='0.15' fill='8'/>
+</g>
+<g id='ww_62'>
+ <circle cx='0' cy='0.3' r='0.15' fill='8'/>
+ <circle cx='0' cy='-0.3' r='0.15' fill='8'/>
+</g>
+<g id='ww_63'>
+ <circle cx='0' cy='0.3' r='0.15' fill='8'/>
+ <circle cx='-0.3' cy='-0.3' r='0.15' fill='8'/>
+ <circle cx='0.3' cy='-0.3' r='0.15' fill='8'/>
+</g>
+<g id='ww_64'>
+ <circle cx='0' cy='0.45' r='0.15' fill='8'/>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
+ <circle cx='0' cy='-0.45' r='0.15' fill='8'/>
+</g>
+<g id='ww_65'>
+ <circle cx='-0.3' cy='0' r='0.15' fill='8'/>
+ <circle cx='0.3' cy='0' r='0.15' fill='8'/>
<circle cx='0' cy='0.45' r='0.15' fill='8'/>
<circle cx='0' cy='-0.45' r='0.15' fill='8'/>
- </g>
-
- <g id='ww_68'>
- <circle cx='0' cy='0.3' r='0.15' fill='8'/>
- <snowflake cx='0' cy='-0.3' r='0.2'/>
- </g>
- <g id='ww_69'>
- <snowflake cx='0' cy='0.45' r='0.2'/>
- <circle cx='0' cy='0' r='0.15' fill='8'/>
- <snowflake cx='0' cy='-0.45' r='0.2'/>
- </g>
- <g id='ww_70'>
+</g>
+<g id='ww_66'>
+ <polyline points='-0.35,-0.1 -0.4,0.05 -0.37,0.1 -0.30,0.15 -0.23,0.15 -0.18,0.1
+ 0.18,-0.1 0.23,-0.15 0.3,-0.15 0.37,-0.1 0.4,-0.05 0.35,0.1' fill='none'/>
+ <snowflake cx='-0.18' cy='-0.2' r='0.2'/>
+</g>
+<g id='ww_67'>
+ <polyline points='-0.35,-0.1 -0.4,0.05 -0.37,0.1 -0.30,0.15 -0.23,0.15 -0.18,0.1
+ 0.18,-0.1 0.23,-0.15 0.3,-0.15 0.37,-0.1 0.4,-0.05 0.35,0.1' fill='none'/>
+ <snowflake cx='-0.18' cy='-0.2' r='0.2'/>
+ <snowflake cx='0.18' cy='0.2' r='0.2'/>
+</g>
+<g id='ww_68'>
+ <circle cx='0' cy='0.3' r='0.15' fill='8'/>
+ <snowflake cx='0' cy='-0.3' r='0.2'/>
+</g>
+<g id='ww_69'>
+ <snowflake cx='0' cy='0.45' r='0.2'/>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
+ <snowflake cx='0' cy='-0.45' r='0.2'/>
+</g>
+<g id='ww_70'>
<snowflake cx='0' cy='0' r='0.2'/>
- </g>
- <g id='ww_71'>
+</g>
+<g id='ww_71'>
<snowflake cx='-0.3' cy='0' r='0.2'/>
<snowflake cx='0.3' cy='0' r='0.2'/>
- </g>
- <g id='ww_72'>
+</g>
+<g id='ww_72'>
<snowflake cx='0' cy='-0.3' r='0.2'/>
<snowflake cx='0' cy='0.3' r='0.2'/>
- </g>
- <g id='ww_73'>
- <snowflake cx='0' cy='0.3' r='0.2'/>
- <snowflake cx='-0.3' cy='-0.3' r='0.2'/>
- <snowflake cx='0.3' cy='-0.3' r='0.2'/>
- </g>
- <g id='ww_74'>
- <snowflake cx='0' cy='0.45' r='0.2'/>
- <snowflake cx='0' cy='0' r='0.2'/>
- <snowflake cx='0' cy='-0.45' r='0.2'/>
- </g>
- <g id='ww_75'>
- <snowflake cx='-0.3' cy='0' r='0.2'/>
- <snowflake cx='0.3' cy='0' r='0.2'/>
+</g>
+<g id='ww_73'>
+ <snowflake cx='0' cy='0.3' r='0.2'/>
+ <snowflake cx='-0.3' cy='-0.3' r='0.2'/>
+ <snowflake cx='0.3' cy='-0.3' r='0.2'/>
+</g>
+<g id='ww_74'>
+ <snowflake cx='0' cy='0.45' r='0.2'/>
+ <snowflake cx='0' cy='0' r='0.2'/>
+ <snowflake cx='0' cy='-0.45' r='0.2'/>
+</g>
+<g id='ww_75'>
+ <snowflake cx='-0.3' cy='0' r='0.2'/>
+ <snowflake cx='0.3' cy='0' r='0.2'/>
<snowflake cx='0' cy='0.45' r='0.2'/>
<snowflake cx='0' cy='-0.45' r='0.2'/>
- </g>
- <g id='ww_76'>
+</g>
+<g id='ww_76'>
<polyline points='-0.45,0 0.45,0' fill='none'/>
<polyline points='-0.3,0.2 -0.45,0. -0.3,-0.2' fill='none'/>
<polyline points='0.3,0.2 0.45,0. 0.3,-0.2' fill='none'/>
- </g>
- <g id='ww_77'>
+</g>
+<g id='ww_77'>
<triangle cx='0' cy='0' r='0.3' fill='0'/>
<polyline points='-0.35,0 0.35,0' fill='none'/>
- </g>
- <g id='ww_78'>
+</g>
+<g id='ww_78'>
<snowflake cx='0' cy='0' r='0.2'/>
<polyline points='-0.35,0 0.35,0' fill='none'/>
- </g>
- <g id='ww_79'>
+</g>
+<g id='ww_79'>
<polyline points='0,0.45 0.4,-0.35 -0.4,-0.35 0,0.45' fill='none'/>
<circle cx='0' cy='0' r='0.05' fill='8'/>
- </g>
- <g id='ww_80'>
- <circle cx='0' cy='0.1' r='0.15' fill='8'/>
+</g>
+<g id='ww_80'>
+ <circle cx='0' cy='0.1' r='0.15' fill='8'/>
<triangle cx='0' cy='-0.3' r='-0.3' fill='0'/>
- </g>
- <g id='ww_81'>
- <circle cx='0' cy='0.15' r='0.15' fill='8'/>
+</g>
+<g id='ww_81'>
+ <circle cx='0' cy='0.15' r='0.15' fill='8'/>
<triangle cx='0' cy='-0.3' r='-0.3' fill='0' line='1'/>
- </g>
- <g id='ww_82'>
- <circle cx='0' cy='0.4' r='0.15' fill='8'/>
- <circle cx='0' cy='0' r='0.15' fill='8'/>
- <triangle cx='0' cy='-0.45' r='-0.3' fill='0'/>
- </g>
- <g id='ww_83'>
- <circle cx='0' cy='0.4' r='0.15' fill='8'/>
- <snowflake cx='0' cy='0' r='0.2'/>
- <triangle cx='0' cy='-0.45' r='-0.3' fill='0'/>
- </g>
- <g id='ww_84'>
- <circle cx='0' cy='0.4' r='0.15' fill='8'/>
- <snowflake cx='0' cy='0' r='0.2'/>
- <triangle cx='0' cy='-0.45' r='-0.3' fill='0' line='1'/>
- </g>
+</g>
+<g id='ww_82'>
+ <circle cx='0' cy='0.4' r='0.15' fill='8'/>
+ <circle cx='0' cy='0' r='0.15' fill='8'/>
+ <triangle cx='0' cy='-0.45' r='-0.3' fill='0'/>
+</g>
+<g id='ww_83'>
+ <circle cx='0' cy='0.4' r='0.15' fill='8'/>
+ <snowflake cx='0' cy='0' r='0.2'/>
+ <triangle cx='0' cy='-0.45' r='-0.3' fill='0'/>
+</g>
+<g id='ww_84'>
+ <circle cx='0' cy='0.4' r='0.15' fill='8'/>
+ <snowflake cx='0' cy='0' r='0.2'/>
+ <triangle cx='0' cy='-0.45' r='-0.3' fill='0' line='1'/>
+</g>
<g id='ww_85'>
<snowflake cx='0' cy='0.3' r='0.2'/>
<triangle cx='0' cy='-0.3' r='-0.3' fill='0'/>
@@ -549,205 +609,210 @@
<triangle cx='0' cy='-0.3' r='-0.3' fill='0' line='1'/>
</g>
<g id='ww_91'>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
- <lightning cx='0' cy='0' r='0.6'/>
- <circle r="0.15" cx="0.75" cy="0" fill="8" />
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <lightning cx='0' cy='0' r='0.6'/>
+ <circle r="0.15" cx="0.75" cy="0" fill="8" />
</g>
<g id='ww_92'>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
- <lightning cx='0' cy='0' r='0.6'/>
- <circle r="0.15" cx="0.75" cy="0.2" fill="8" />
- <circle r="0.15" cx="0.75" cy="-0.2" fill="8" />
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <lightning cx='0' cy='0' r='0.6'/>
+ <circle r="0.15" cx="0.75" cy="0.2" fill="8" />
+ <circle r="0.15" cx="0.75" cy="-0.2" fill="8" />
</g>
<g id='ww_93'>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
- <lightning cx='0' cy='0' r='0.6'/>
- <snowflake cx='0.7' cy='0.3' r='0.2'/>
- <polyline points='0.6,-0.3 1.,0.3' fill='none'/>
- <triangle cx='1,' cy='-0.3' r='0.3' fill='0'/>
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <lightning cx='0' cy='0' r='0.6'/>
+ <snowflake cx='0.7' cy='0.3' r='0.2'/>
+ <polyline points='0.6,-0.3 1.,0.3' fill='none'/>
+ <triangle cx='1,' cy='-0.3' r='0.3' fill='0'/>
</g>
<g id='ww_94'>
- <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
- <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
- <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
- <lightning cx='0' cy='0' r='0.6'/>
-
- <triangle cx='0.6' cy='-0.35' r='0.2' fill='0'/>
- <triangle cx='0.9' cy='0.35' r='0.2' fill='0'/>
+ <polyline points='0.5,-0.45 0.5,0.45' fill='none'/>
+ <polyline points='0.5,-0.45 0.35,-0.45' fill='none'/>
+ <polyline points='0.5,0.45 0.35,0.45' fill='none'/>
+ <lightning cx='0' cy='0' r='0.6'/>
+ <triangle cx='0.7' cy='-0.3' r='0.2' fill='0'/>
+ <triangle cx='0.7' cy='0.3' r='0.2' fill='0'/>
</g>
<g id="ww_95">
- <circle r="0.1" cx="0." cy="0.6" fill="8" />
- <lightning cx='0' cy='0' r='0.4'/>
+ <circle r="0.1" cx="0." cy="0.6" fill="8" />
+ <lightning cx='0' cy='0' r='0.4'/>
</g>
<g id="ww_96">
- <triangle cx='0' cy='0.55' r='0.2' fill='0' />
- <lightning cx='0' cy='0' r='0.5'/>
+ <triangle cx='0' cy='0.55' r='0.2' fill='0' />
+ <lightning cx='0' cy='0' r='0.5'/>
</g>
<g id="ww_97">
<circle r="0.1" cx="0." cy="0.6" fill="8" />
<lightning cx='0' cy='0' r='0.4'/>
</g>
-
+<g id="ww_98">
+ <polyline points='0.2,0.45 0.1,0.49 0,0.5 -0.1,0.49 -0.2,0.46 -0.2,0.4 -0.16,0.38 0,0.3
+ 0.16,0.22 0.2,0.2 0.2,0.14 0.1,0.11 0,0.1 -0.1,0.11 -0.2,0.15' fill='none'/>
+ <polyline points='-0.28,0.3 0.28,0.3' fill='none'/>
+ <polyline points='0.3,0.3 0.14,0.37' fill='none'/>
+ <polyline points='0.3,0.3 0.14,0.23' fill='none'/>
+ <lightning cx='0' cy='-0.15' r='0.35'/>
+</g>
<g id="ww_99">
- <triangle cx='0' cy='0.55' r='0.3' fill='0' />
- <lightning cx='0' cy='0' r='0.4'/>
+ <triangle cx='0' cy='0.55' r='0.3' fill='0' />
+ <lightning cx='0' cy='0' r='0.4'/>
</g>
- <g id='N_0'>
+
+<g id='N_0'>
<circle cx='0' cy='0' r='0.5' fill='0'/>
- </g>
- <g id='N_1'>
+</g>
+<g id='N_1'>
<circle cx='0' cy='0' r='0.5' fill='0'/>
<polyline points='0,0.5 0,-0.5' fill='none'/>
- </g>
- <g id='N_2'>
+</g>
+<g id='N_2'>
<circle cx='0' cy='0' r='0.5' fill='2'/>
- </g>
- <g id='N_3'>
+</g>
+<g id='N_3'>
<circle cx='0' cy='0' r='0.5' fill='2'/>
<polyline points='0,0.5 0,-0.5' fill='none'/>
- </g>
- <g id='N_4'>
+</g>
+<g id='N_4'>
<circle cx='0' cy='0' r='0.5' fill='4'/>
- </g>
- <g id='N_5'>
+</g>
+<g id='N_5'>
<circle cx='0' cy='0' r='0.5' fill='4'/>
<polyline points='0.5,0 -0.5,0' fill='none'/>
- </g>
- <g id='N_6'>
+</g>
+<g id='N_6'>
<circle cx='0' cy='0' r='0.5' fill='6'/>
- </g>
- <g id='N_7'>
+</g>
+<g id='N_7'>
<circle cx='0' cy='0' r='0.5' fill='9'/>
- </g>
- <g id='N_8'>
+</g>
+<g id='N_8'>
<circle cx='0' cy='0' r='0.5' fill='8'/>
- </g>
- <g id='N_9'>
+</g>
+<g id='N_9'>
<circle cx='0' cy='0' r='0.5' fill='0'/>
<polyline points='0.354,0.354 -0.354,-0.354' fill='none'/>
<polyline points='-0.354,0.354 0.354,-0.354' fill='none'/>
- </g>
- <g id='N_/'>
- <circle cx='0' cy='0' r='0.5' fill='0'/>
- <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
+</g>
+<g id='N_/'>
+ <circle cx='0' cy='0' r='0.5' fill='0'/>
+ <polyline points='-0.5,-0.5 0.5,0.5' fill='none'/>
<polyline points='-0.5,0.5 0.5,-0.5' fill='none'/>
- </g>
+</g>
- <g id='W_0'>
+<g id='W_0'>
<circle cx='0' cy='0' r='0.5' fill='0'/>
- </g>
- <g id='W_1'>
+</g>
+<g id='W_1'>
<circle cx='0' cy='0' r='0.5' fill='4'/>
- </g>
- <g id='W_2'>
+</g>
+<g id='W_2'>
<circle cx='0' cy='0' r='0.5' fill='9'/>
- </g>
- <g id='W_3'>
- <polyline points='-0.38,0 0.38,0' fill='none'/>
- <polyline points='0.4,0 0.22,0.13' fill='none'/>
- <polyline points='0.4,0 0.22,-0.13' fill='none'/>
- <polyline points='0,0.4 0,-0.38' fill='none'/>
- <polyline points='0,0.4 -0.13,0.22' fill='none'/>
- <polyline points='0,0.4 0.13,0.22' fill='none'/>
- </g>
- <g id='W_4'>
- <polyline points='-0.3,0.3 0.3,0.3' fill='none'/>
- <polyline points='-0.3,0 0.3,0' fill='none'/>
- <polyline points='-0.3,-0.3 0.3,-0.3' fill='none'/>
- </g>
- <g id='W_5'>
- <drizzle cx='0' cy='0' r='0.2'/>
- </g>
- <g id='W_6'>
- <circle cx='0' cy='0' r='0.2' fill='8'/>
- </g>
- <g id='W_7'>
- <snowflake cx='0' cy='0' r='0.2'/>
- </g>
- <g id='W_8'>
- <polyline points='0.2,0.2 0,-0.3 -0.2,0.2 0.2,0.2 0' fill='none'/>
- </g>
- <g id='W_9'>
- <lightning cx='0' cy='0.3' r='0.5'/>
- </g>
- <g id='W_/'>
- </g>
+</g>
+<g id='W_3'>
+ <polyline points='-0.38,0 0.38,0' fill='none'/>
+ <polyline points='0.4,0 0.22,0.13' fill='none'/>
+ <polyline points='0.4,0 0.22,-0.13' fill='none'/>
+ <polyline points='0,0.4 0,-0.38' fill='none'/>
+ <polyline points='0,0.4 -0.13,0.22' fill='none'/>
+ <polyline points='0,0.4 0.13,0.22' fill='none'/>
+</g>
+<g id='W_4'>
+ <polyline points='-0.3,0.3 0.3,0.3' fill='none'/>
+ <polyline points='-0.3,0 0.3,0' fill='none'/>
+ <polyline points='-0.3,-0.3 0.3,-0.3' fill='none'/>
+</g>
+<g id='W_5'>
+ <drizzle cx='0' cy='0' r='0.2'/>
+</g>
+<g id='W_6'>
+ <circle cx='0' cy='0' r='0.2' fill='8'/>
+</g>
+<g id='W_7'>
+ <snowflake cx='0' cy='0' r='0.2'/>
+</g>
+<g id='W_8'>
+ <polyline points='0.2,0.2 0,-0.3 -0.2,0.2 0.2,0.2 0' fill='none'/>
+</g>
+<g id='W_9'>
+ <lightning cx='0' cy='0.3' r='0.7'/>
+</g>
- <g id='CL_0'>
- </g>
- <g id='CL_1'>
- <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
- </g>
- <g id='CL_2'>
- <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+<g id='CL_0'>
+</g>
+<g id='CL_1'>
+ <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+</g>
+<g id='CL_2'>
+ <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
<polyline points='0.25,0.3 0.27,0.4 0.2,0.51 0.05,0.57 -0.05,0.57 -0.2,0.51 -0.27,0.4 -0.25,0.3' fill='none'/>
- </g>
- <g id='CL_3'>
- <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+</g>
+<g id='CL_3'>
+ <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
<polyline points='0.25,0.3 0.27,0.4 0.2,0.51 0.05,0.57 -0.05,0.57 -0.2,0.51 -0.27,0.4 -0.25,0.3' fill='none'/>
<polyline points='0,0.57 0,0.1' fill='none'/>
- </g>
- <g id='CL_4'>
- <polyline points='0.43,-0.1 0.34,0.14 0.25,0.28 0.1,0.33 -0.1,0.33 -0.25,0.28 -0.34,0.14 -0.43,-0.1' fill='none'/>
- <polyline points='-0.52,-0.1 -0.2,-0.1 -0.1,-0.2 0.1,-0.2 0.2,-0.1 0.52,-0.1' fill='none'/>
- </g>
- <g id='CL_5'>
- <polyline points='-0.5,0.2 -0.22,0.2 -0.1,0. 0.1,0. 0.22,0.2 0.5,0.2' fill='none'/>
- </g>
- <g id='CL_6'>
- <polyline points='0.3,0 -0.3,0' fill='none'/>
- </g>
- <g id='CL_7'>
- <polyline points='-0.4,0 -0.2,0' fill='none'/>
- <polyline points='-0.1,0 0.1,0' fill='none'/>
- <polyline points='0.2,0 0.4,0' fill='none'/>
- </g>
- <g id='CL_8'>
- <polyline points='-0.5,0.5 -0.2,0.5 -0.1,0.4 0.1,0.4 0.2,0.5 0.5,0.5' fill='none'/>
- <polyline points='-0.5,-0.2 0.5,-0.2 0.4,0.06 0.23,0.2 0.1,0.22 -0.1,0.22 -0.23,0.2 -0.4,0.06 -0.5,-0.2' fill='none'/>
- </g>
- <g id='CL_9'>
- <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+</g>
+<g id='CL_4'>
+ <polyline points='0.43,-0.1 0.34,0.14 0.25,0.28 0.1,0.33 -0.1,0.33 -0.25,0.28 -0.34,0.14 -0.43,-0.1' fill='none'/>
+ <polyline points='-0.52,-0.1 -0.2,-0.1 -0.1,-0.2 0.1,-0.2 0.2,-0.1 0.52,-0.1' fill='none'/>
+</g>
+<g id='CL_5'>
+ <polyline points='-0.5,0.2 -0.22,0.2 -0.1,0. 0.1,0. 0.22,0.2 0.5,0.2' fill='none'/>
+</g>
+<g id='CL_6'>
+ <polyline points='0.3,0 -0.3,0' fill='none'/>
+</g>
+<g id='CL_7'>
+ <polyline points='-0.4,0 -0.2,0' fill='none'/>
+ <polyline points='-0.1,0 0.1,0' fill='none'/>
+ <polyline points='0.2,0 0.4,0' fill='none'/>
+</g>
+<g id='CL_8'>
+ <polyline points='-0.5,0.5 -0.2,0.5 -0.1,0.4 0.1,0.4 0.2,0.5 0.5,0.5' fill='none'/>
+ <polyline points='-0.5,-0.2 0.5,-0.2 0.4,0.06 0.23,0.2 0.1,0.22 -0.1,0.22 -0.23,0.2 -0.4,0.06 -0.5,-0.2' fill='none'/>
+</g>
+<g id='CL_9'>
+ <polyline points='-0.5,-0.1 0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
<polyline points='0.25,0.3 0.32,0.55 -0.32,0.55 -0.25,0.3' fill='none'/>
- </g>
- <g id='CL_/'>
- </g>
+</g>
+<g id='CL_/'>
+</g>
- <g id='CM_0'>
- </g>
- <g id='CM_1'>
- <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
- </g>
- <g id='CM_2'>
- <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
- <polyline points='0,0 0.3,0.15' fill='none'/>
- </g>
- <g id='CM_3'>
- <polyline points='-0.4,0 -0.3,-0.2 -0.1,-0.2 0,0 0.1,-0.2 0.3,-0.2 0.4,0' fill='none'/>
- </g>
- <g id='CM_4'>
- <polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0' fill='none'/>
- </g>
+<g id='CM_0'>
+</g>
+<g id='CM_1'>
+ <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
+</g>
+<g id='CM_2'>
+ <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
+ <polyline points='0,0 0.3,0.15' fill='none'/>
+</g>
+<g id='CM_3'>
+ <polyline points='-0.4,0 -0.3,-0.2 -0.1,-0.2 0,0 0.1,-0.2 0.3,-0.2 0.4,0' fill='none'/>
+</g>
+<g id='CM_4'>
+ <polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0' fill='none'/>
+</g>
<g id='CM_5'>
<polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0 0.1,-0.2 0.3,-0.2 0.4,0' fill='none'/>
</g>
- <g id='CM_6'>
- <polyline points='-0.4,0.3 -0.3,0.1 -0.1,0.1 0,0.3 0.1,0.1 0.3,0.1 0.4,0.3' fill='none'/>
- <polyline points='0.5,-0.4 0.4,-0.14 0.23,0 0.1,0.02 -0.1,0.02 -0.23,0 -0.4,-0.14 -0.5,-0.4' fill='none'/>
- </g>
- <g id='CM_7'>
- <polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0 0.1,-0.2 0.3,-0.2 0.4,0' fill='none'/>
- <polyline points='-0.4,0 0.4,0' fill='none'/>
- </g>
- <g id='CM_8'>
- <polyline points='-0.3,-0.35 -0.3,0.35 -0.15,0.29 -0.05,0.25 0,0.23 0.05,0.25 0.15,0.29 0.3,0.35 0.3,-0.35' fill='none'/>
- </g>
+<g id='CM_6'>
+ <polyline points='-0.4,0.3 -0.3,0.1 -0.1,0.1 0,0.3 0.1,0.1 0.3,0.1 0.4,0.3' fill='none'/>
+ <polyline points='0.5,-0.4 0.4,-0.14 0.23,0 0.1,0.02 -0.1,0.02 -0.23,0 -0.4,-0.14 -0.5,-0.4' fill='none'/>
+</g>
+<g id='CM_7'>
+ <polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0 0.1,-0.2 0.3,-0.2 0.4,0' fill='none'/>
+ <polyline points='-0.4,0 0.4,0' fill='none'/>
+</g>
+<g id='CM_8'>
+ <polyline points='-0.3,-0.35 -0.3,0.35 -0.15,0.29 -0.05,0.25 0,0.23 0.05,0.25 0.15,0.29 0.3,0.35 0.3,-0.35' fill='none'/>
+</g>
<g id='CM_9'>
<polyline points='0.2,0.3 -0.4,0 -0.3,-0.2 -0.1,-0.2 0,0' fill='none'/>
<polyline points='-0.45,0 -0.31,-0.25 -0.09,-0.25 0.05,0' fill='none'/>
@@ -758,20 +823,24 @@
<g id='CH_0'>
</g>
<g id='CH_1'>
- <polyline points='-0.3,0 0.28,0 0.29,0.06 0.3,0.1 0.29,0.14 0.28,0.2' fill='none'/>
+ <polyline points='-0.3,0 0.28,0 0.29,0.06 0.3,0.1 0.29,0.14 0.28,0.2 0.2,0.22' fill='none'/>
</g>
<g id='CH_2'>
- <polyline points='-0.3,0 0.28,0 0.29,0.06 0.3,0.1 0.29,0.14 0.28,0.2' fill='none'/>
- <polyline points='0.18,0 0.19,0.06 0.2,0.1 0.19,0.14 0.18,0.2' fill='none'/>
+ <polyline points='-0.3,0 0.28,0 0.29,0.06 0.3,0.1 0.29,0.14 0.28,0.2 0.2,0.22' fill='none'/>
+ <polyline points='0.18,0 0.19,0.06 0.2,0.1 0.19,0.14 0.18,0.2 0.1,0.22' fill='none'/>
</g>
<g id='CH_3'>
- <polyline points='-0.3,0 0.28,0 0.29,-0.06 0.3,-0.1 0.29,-0.14 0.28,-0.2' fill='none'/>
+ <polyline points='-0.3,0 0.28,0 0.29,-0.06 0.3,-0.1 0.29,-0.14 0.28,-0.2 0.2,-0.22' fill='none'/>
+</g>
+<g id='CH_4'>
+ <polyline points='-0.35,-0.4 0.35,0.4 0.32,0.44 0.25,0.48 0.15,0.44 ' fill='none'/>
</g>
-
<g id='CH_5'>
<polyline points='-0.3,0.2 -0.29,0.14 -0.28,0.1 -0.29,0.06 -0.3,0 0.3,0' fill='none'/>
</g>
-
+<g id='CH_6'>
+ <polyline points='-0.1,-0.4 -0.35,-0.4 0.35,0.4 0.32,0.44 0.25,0.48 0.15,0.44 ' fill='none'/>
+</g>
<g id='CH_7'>
<polyline points='-0.3,0.2 -0.29,0.14 -0.28,0.1 -0.29,0.06 -0.3,0 0.3,0 0.29,0.06 0.28,0.1 0.29,0.14 0.3,0.2' fill='none'/>
</g>
@@ -783,126 +852,142 @@
</g>
<g id='CH_/'>
</g>
-
- <g id='C_4'>
- <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
- <polyline points='0,0 0.15,0.075' fill='none'/>
- </g>
- <g id='C_5'>
- <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
- <polyline points='0,0 0.3,0.15 0.3,0' fill='none'/>
- </g>
- <g id='C_7'>
- <polyline points='-0.3,0 -0.1,0' fill='none'/>
- <polyline points='0.1,0 0.3,0' fill='none'/>
- </g>
- <g id='C_8'>
- <polyline points='0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
- <polyline points='0.25,0.3 0.27,0.4 0.2,0.51 0.05,0.57 -0.05,0.57 -0.2,0.51 -0.27,0.4 -0.25,0.3' fill='none'/>
- </g>
- <g id='C_9'>
- <polyline points='0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
- <polyline points='0.25,0.3 0.32,0.55 -0.32,0.55 -0.25,0.3' fill='none'/>
- </g>
- <g id='C_/'>
- </g>
-
- <g id='a_0'>
- <polyline points='-0.4,-0.4 0.1,0.4 0.3,0.2' fill='none'/>
- </g>
- <g id='a_1'>
- <polyline points='-0.4,-0.4 0.05,0.4 0.35,0.4' fill='none'/>
- </g>
- <g id='a_2'>
- <polyline points='-0.3,-0.4 0.3,0.4' fill='none'/>
- </g>
- <g id='a_3'>
- <polyline points='-0.3,-0.2 -0.05,-0.4 0.4,0.4' fill='none'/>
- </g>
- <g id='a_4'>
- </g>
- <g id='a_5'>
- <polyline points='-0.4,0.4 0.05,-0.4 0.3,-0.2' fill='none'/>
- </g>
- <g id='a_6'>
- <polyline points='-0.4,0.4 0.05,-0.4 0.35,-0.4' fill='none'/>
- </g>
- <g id='a_7'>
- <polyline points='-0.3,0.4 0.3,-0.4' fill='none'/>
- </g>
- <g id='a_8'>
- <polyline points='-0.3,0.2 -0.05,0.4 0.4,-0.4' fill='none'/>
- </g>
- <g id='a_9'>
- </g>
- <g id='a_/'>
- </g>
- <g id='DS_0'>
- </g>
- <g id='DS_1'>
- <polyline points='-0.4,-0.4 0.4,0.4' fill='none'/>
- <polyline points='0.4,0.4 0.33,0.12' fill='none'/>
- <polyline points='0.4,0.4 0.12,0.33' fill='none'/>
- </g>
- <g id='DS_2'>
- <polyline points='-0.4,0 0.4,0' fill='none'/>
- <polyline points='0.4,0 0.14,0.15' fill='none'/>
- <polyline points='0.4,0 0.14,-0.15' fill='none'/>
- </g>
- <g id='DS_3'>
- <polyline points='-0.4,0.4 0.4,-0.4' fill='none'/>
- <polyline points='0.4,-0.4 0.33,-0.12' fill='none'/>
- <polyline points='0.4,-0.4 0.12,-0.33' fill='none'/>
- </g>
- <g id='DS_4'>
- <polyline points='0,-0.4 0,0.4' fill='none'/>
- <polyline points='0,-0.4 -0.15,-0.14' fill='none'/>
- <polyline points='0,-0.4 0.15,-0.14' fill='none'/>
- </g>
- <g id='DS_5'>
- <polyline points='-0.4,-0.4 0.4,0.4' fill='none'/>
- <polyline points='-0.4,-0.4 -0.33,-0.12' fill='none'/>
- <polyline points='-0.4,-0.4 -0.12,-0.33' fill='none'/>
- </g>
- <g id='DS_6'>
- <polyline points='-0.4,0 0.4,0' fill='none'/>
- <polyline points='-0.4,0 -0.14,0.15' fill='none'/>
- <polyline points='-0.4,0 -0.14,-0.15' fill='none'/>
- </g>
- <g id='DS_7'>
- <polyline points='-0.4,0.4 0.4,-0.4' fill='none'/>
- <polyline points='-0.4,0.4 -0.33,0.12' fill='none'/>
- <polyline points='-0.4,0.4 -0.12,0.33' fill='none'/>
- </g>
- <g id='DS_8'>
- <polyline points='0,-0.4 0,0.4' fill='none'/>
- <polyline points='0,0.4 -0.15,0.14' fill='none'/>
- <polyline points='0,0.4 0.15,0.14' fill='none'/>
- </g>
+<g id='C_0'>
+ <polyline points='-0.3,0 0.28,0 0.29,0.06 0.3,0.1 0.29,0.14 0.28,0.2 0.2,0.22' fill='none'/>
+ <polyline points='0.28,0 0.29,-0.06 0.3,-0.1 0.29,-0.14 0.28,-0.2 0.2,-0.22' fill='none'/>
+</g>
+<g id='C_1'>
+ <polyline points='-0.15,-0.44 -0.25,-0.48 -0.32,-0.44 -0.35,-0.4 0.35,0.4 0.32,0.44 0.25,0.48 0.15,0.44' fill='none'/>
+</g>
+<g id='C_2'>
+ <polyline points='0.4,-0.4 -0.35,-0.4 0.35,0.4 0.32,0.44 0.25,0.48 0.15,0.44 ' fill='none'/>
+</g>
+<g id='C_3'>
+ <polyline points='-0.35,0.3 -0.35,0.15 -0.33,0.1 -0.3,0.0 -0.25,-0.1 -0.1,-0.19 0.,-0.2
+ 0.1,-0.19 0.25,-0.1 0.3,0.0 0.33,0.1 0.35,0.15 0.35,0.3' fill='none'/>
+</g>
+<g id='C_4'>
+ <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
+ <polyline points='0,0 0.15,0.075' fill='none'/>
+</g>
+<g id='C_5'>
+ <polyline points='0.3,0 -0.3,0 0.3,0.3' fill='none'/>
+ <polyline points='0,0 0.3,0.15 0.3,0' fill='none'/>
+</g>
+<g id='C_6'>
+ <polyline points='-0.5, 0.1 -0.22, 0.1 -0.1, .3 0.1, .3 0.22, 0.1 0.5, 0.1' fill='none'/>
+ <polyline points='-0.5,-0.1 -0.22,-0.1 -0.1,-.3 0.1,-.3 0.22,-0.1 0.5,-0.1' fill='none'/>
+</g>
+<g id='C_7'>
+ <polyline points='-0.3,0 -0.1,0' fill='none'/>
+ <polyline points='0.1,0 0.3,0' fill='none'/>
+</g>
+<g id='C_8'>
+ <polyline points='0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+ <polyline points='0.25,0.3 0.27,0.4 0.2,0.51 0.05,0.57 -0.05,0.57 -0.2,0.51 -0.27,0.4 -0.25,0.3' fill='none'/>
+</g>
+<g id='C_9'>
+ <polyline points='0.5,-0.1 0.4,0.16 0.25,0.3 0.1,0.35 -0.1,0.35 -0.25,0.3 -0.4,0.16 -0.5,-0.1' fill='none'/>
+ <polyline points='0.25,0.3 0.32,0.55 -0.32,0.55 -0.25,0.3' fill='none'/>
+</g>
+<g id='C_/'>
+</g>
+<g id='a_0'>
+ <polyline points='-0.4,-0.4 0.1,0.4 0.3,0.2' fill='none'/>
+</g>
+<g id='a_1'>
+ <polyline points='-0.4,-0.4 0.05,0.4 0.35,0.4' fill='none'/>
+</g>
+<g id='a_2'>
+ <polyline points='-0.3,-0.4 0.3,0.4' fill='none'/>
+</g>
+<g id='a_3'>
+ <polyline points='-0.3,-0.2 -0.05,-0.4 0.4,0.4' fill='none'/>
+</g>
+<g id='a_4'>
+</g>
+<g id='a_5'>
+ <polyline points='-0.4,0.4 0.05,-0.4 0.3,-0.2' fill='none'/>
+</g>
+<g id='a_6'>
+ <polyline points='-0.4,0.4 0.05,-0.4 0.35,-0.4' fill='none'/>
+</g>
+<g id='a_7'>
+ <polyline points='-0.3,0.4 0.3,-0.4' fill='none'/>
+</g>
+<g id='a_8'>
+ <polyline points='-0.3,0.2 -0.05,0.4 0.4,-0.4' fill='none'/>
+</g>
+<g id='a_9'>
+</g>
+<g id='a_/'>
+</g>
- <g id='DS_9'>
- </g>
- <g id='DS_/'>
- </g>
+<g id='DS_0'>
+</g>
+<g id='DS_1'>
+ <polyline points='-0.4,-0.4 0.4,0.4' fill='none'/>
+ <polyline points='0.4,0.4 0.33,0.12' fill='none'/>
+ <polyline points='0.4,0.4 0.12,0.33' fill='none'/>
+</g>
+<g id='DS_2'>
+ <polyline points='-0.4,0 0.4,0' fill='none'/>
+ <polyline points='0.4,0 0.14,0.15' fill='none'/>
+ <polyline points='0.4,0 0.14,-0.15' fill='none'/>
+</g>
+<g id='DS_3'>
+ <polyline points='-0.4,0.4 0.4,-0.4' fill='none'/>
+ <polyline points='0.4,-0.4 0.33,-0.12' fill='none'/>
+ <polyline points='0.4,-0.4 0.12,-0.33' fill='none'/>
+</g>
+<g id='DS_4'>
+ <polyline points='0,-0.4 0,0.4' fill='none'/>
+ <polyline points='0,-0.4 -0.15,-0.14' fill='none'/>
+ <polyline points='0,-0.4 0.15,-0.14' fill='none'/>
+</g>
+<g id='DS_5'>
+ <polyline points='-0.4,-0.4 0.4,0.4' fill='none'/>
+ <polyline points='-0.4,-0.4 -0.33,-0.12' fill='none'/>
+ <polyline points='-0.4,-0.4 -0.12,-0.33' fill='none'/>
+</g>
+<g id='DS_6'>
+ <polyline points='-0.4,0 0.4,0' fill='none'/>
+ <polyline points='-0.4,0 -0.14,0.15' fill='none'/>
+ <polyline points='-0.4,0 -0.14,-0.15' fill='none'/>
+</g>
+<g id='DS_7'>
+ <polyline points='-0.4,0.4 0.4,-0.4' fill='none'/>
+ <polyline points='-0.4,0.4 -0.33,0.12' fill='none'/>
+ <polyline points='-0.4,0.4 -0.12,0.33' fill='none'/>
+</g>
+<g id='DS_8'>
+ <polyline points='0,-0.4 0,0.4' fill='none'/>
+ <polyline points='0,0.4 -0.15,0.14' fill='none'/>
+ <polyline points='0,0.4 0.15,0.14' fill='none'/>
+</g>
+<g id='DS_9'>
+</g>
+<g id='DS_/'>
+</g>
- <g id='logo_ecmwf'>
- <!-- top -->
- <polyline points='-3.375,0.125 -3.3,0.325 -3.15,0.5 -3,0.575 -2.85,0.6 -2.75,0.6 -2.5,0.55 -2.25,0.6 -2.2,0.6 -2.05,0.56 -1.85,0.44 -1.725,0.3 -1.675,0.125 -2.025,0.125 -2.125,0.225 -2.25,0.25 -2.375,0.2375 -2.45,0.175 -2.5,0.0875 -2.525,0.0875 -2.5625,0.175 -2.6625,0.2375 -2.775,0.25 -2.9,0.225 -3,0.125 -3.375,0.125' fill='blue'/>
- <!-- bottom -->
- <polyline points='-3.375,-0.125 -3.3,-0.325 -3.15,-0.5 -3,-0.575 -2.85,-0.6 -2.75,-0.6 -2.5,-0.55 -2.25,-0.6 -2.2,-0.6 -2.05,-0.56 -1.85,-0.44 -1.725,-0.3 -1.675,-0.125 -2.025,-0.125 -2.125,-0.225 -2.25,-0.25 -2.375,-0.2375 -2.45,-0.175 -2.5,-0.0875 -2.525,-0.0875 -2.5625,-0.175 -2.6625,-0.2375 -2.775,-0.25 -2.9,-0.225 -3,-0.125 -3.375,-0.125' fill='blue'/>
- <!-- line -->
- <polyline points='-3.4,-0.065 -3.4,0.065 -2.9,0.065 -2.9,-0.065 -3.4,-0.065' fill='blue'/>
- <!-- E -->
- <polyline points='-1.575,-.5 -1.575,.5 -0.825,.5 -0.825,.4 -0.925,.3 -1.2,.3 -1.2,.1 -1,.1 -1,-0.125 -1.2,-0.125 -1.2,-0.275 -0.925,-0.275 -0.825,-0.425 -0.825,-.5 -1.575,-.5' fill='blue'/>
- <!-- C -->
- <polyline points='-.025,0.175 -.025,0.45 -0.175,0.5 -0.3,0.51 -0.475,0.51 -0.6625,0.45 -0.75,0.4 -0.875,0.2875 -0.95,0.1 -0.95,-0.075 -0.9,-0.2375 -0.8,-0.375 -0.475,-0.51 -0.35,-0.51 -0.15,-0.495 -.025,-0.425 -.025,-0.1625 -.2,-0.225 -0.4,-0.2375 -0.5375,-0.1625 -.6,-0.075 -.6,0.075 -.5,0.2 -0.375,0.2375 -0.2125,0.225 -.025,0.175' fill='blue'/>
- <!-- M -->
- <polyline points='0.028,-0.5 0.028,0.5 0.35,0.5 0.625,0.125 0.9,0.5 1.225,0.5 1.225,-0.5 0.9,-0.5 0.9,0 0.625,-0.325 0.35,0 0.35,-0.5 0.028,-0.5' fill='blue'/>
- <!-- W -->
- <polyline points='1.3,0.2 1.3,0.5 1.55,0.5 1.675,0.075 1.8,0.5 2.05,0.5 2.175,0.075 2.3,0.5 2.55,0.5 2.55,0.2 2.275,-0.5 2.05,-0.5 1.925,-0.05 1.8,-0.5 1.575,-0.5 1.3,0.2' fill='blue'/>
- <!-- F -->
- <polyline points='2.625,-0.5 2.625,0.5 3.375,0.5 3.375,0.3 3,0.3 3,0.125 3.35,0.125 3.35,-0.1 3,-0.1 3,-0.5 2.625,-0.5' fill='blue'/>
- </g>
+<g id='logo_ecmwf'>
+<!-- top -->
+ <polyline points='-3.375,0.125 -3.3,0.325 -3.15,0.5 -3,0.575 -2.85,0.6 -2.75,0.6 -2.5,0.55 -2.25,0.6 -2.2,0.6 -2.05,0.56 -1.85,0.44 -1.725,0.3 -1.675,0.125 -2.025,0.125 -2.125,0.225 -2.25,0.25 -2.375,0.2375 -2.45,0.175 -2.5,0.0875 -2.525,0.0875 -2.5625,0.175 -2.6625,0.2375 -2.775,0.25 -2.9,0.225 -3,0.125 -3.375,0.125' fill='blue'/>
+ <!-- bottom -->
+ <polyline points='-3.375,-0.125 -3.3,-0.325 -3.15,-0.5 -3,-0.575 -2.85,-0.6 -2.75,-0.6 -2.5,-0.55 -2.25,-0.6 -2.2,-0.6 -2.05,-0.56 -1.85,-0.44 -1.725,-0.3 -1.675,-0.125 -2.025,-0.125 -2.125,-0.225 -2.25,-0.25 -2.375,-0.2375 -2.45,-0.175 -2.5,-0.0875 -2.525,-0.0875 -2.5625,-0.175 -2.6625,-0.2375 -2.775,-0.25 -2.9,-0.225 -3,-0.125 -3.375,-0.125' fill='blue'/>
+ <!-- line -->
+ <polyline points='-3.4,-0.065 -3.4,0.065 -2.9,0.065 -2.9,-0.065 -3.4,-0.065' fill='blue'/>
+ <!-- E -->
+ <polyline points='-1.575,-.5 -1.575,.5 -0.825,.5 -0.825,.4 -0.925,.3 -1.2,.3 -1.2,.1 -1,.1 -1,-0.125 -1.2,-0.125 -1.2,-0.275 -0.925,-0.275 -0.825,-0.425 -0.825,-.5 -1.575,-.5' fill='blue'/>
+ <!-- C -->
+ <polyline points='-.025,0.175 -.025,0.45 -0.175,0.5 -0.3,0.51 -0.475,0.51 -0.6625,0.45 -0.75,0.4 -0.875,0.2875 -0.95,0.1 -0.95,-0.075 -0.9,-0.2375 -0.8,-0.375 -0.475,-0.51 -0.35,-0.51 -0.15,-0.495 -.025,-0.425 -.025,-0.1625 -.2,-0.225 -0.4,-0.2375 -0.5375,-0.1625 -.6,-0.075 -.6,0.075 -.5,0.2 -0.375,0.2375 -0.2125,0.225 -.025,0.175' fill='blue'/>
+ <!-- M -->
+ <polyline points='0.028,-0.5 0.028,0.5 0.35,0.5 0.625,0.125 0.9,0.5 1.225,0.5 1.225,-0.5 0.9,-0.5 0.9,0 0.625,-0.325 0.35,0 0.35,-0.5 0.028,-0.5' fill='blue'/>
+ <!-- W -->
+ <polyline points='1.3,0.2 1.3,0.5 1.55,0.5 1.675,0.075 1.8,0.5 2.05,0.5 2.175,0.075 2.3,0.5 2.55,0.5 2.55,0.2 2.275,-0.5 2.05,-0.5 1.925,-0.05 1.8,-0.5 1.575,-0.5 1.3,0.2' fill='blue'/>
+ <!-- F -->
+ <polyline points='2.625,-0.5 2.625,0.5 3.375,0.5 3.375,0.3 3,0.3 3,0.125 3.35,0.125 3.35,-0.1 3,-0.1 3,-0.5 2.625,-0.5' fill='blue'/>
+</g>
</svg>
diff --git a/share/magics/title_template.xml b/share/magics/title_template.xml
index 4808de1..b392dad 100644
--- a/share/magics/title_template.xml
+++ b/share/magics/title_template.xml
@@ -30,6 +30,10 @@
<text><base_date format = '%A %d %B %Y %H UTC'/> <centre format = "%s Forecast"/> <step format="t+%s"/>
<valid_date format = 'VT:%A %d %B %Y %H UTC'/> <level/> <parameter/><units/><expver/></text>
</title>
+ <title timeRangeIndicator='10'>
+ <text><base_date format = '%A %d %B %Y %H UTC'/> <centre format = "%s Forecast"/> <step format="t+%s"/>
+<valid_date format = 'VT:%A %d %B %Y %H UTC'/> <level/> <parameter/><units/><expver/></text>
+ </title>
<title dataType='fc'>
<text><base_date format = '%A %d %B %Y %H UTC'/> <centre/> <product/> <step format="t+%s"/>
<valid_date format = 'VT:%A %d %B %Y %H UTC'/> <level/> <parameter/><units/><expver/></text>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0935709..3d1ba7d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,10 +1,8 @@
###############################################################################
configure_file( magics_config.h.in magics_config.h )
-configure_file( magics.pc.in magics.pc @ONLY )
install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/magics_config.h DESTINATION ${INSTALL_INCLUDE_DIR})
-install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/magics.pc DESTINATION ${INSTALL_LIB_DIR}/pkgconfig)
###############################################################################
@@ -16,7 +14,7 @@ function( add_metview_definition_file )
add_custom_command(
OUTPUT ${_p_BASENAME}Def ${_p_BASENAME}Rules
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xml2mv.py ${CMAKE_CURRENT_SOURCE_DIR} ${_p_FILE} ${_p_BASENAME}Def ${_p_ACTION} ${_p_BASENAME}Rules
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/xml2mv.py ${CMAKE_CURRENT_SOURCE_DIR} ${_p_FILE} ${_p_BASENAME}Def ${_p_ACTION} ${_p_BASENAME}Rules
DEPENDS ${_p_FILE}
)
@@ -40,7 +38,7 @@ foreach( file ${magics_xmls} )
# generate the code
add_custom_command(
OUTPUT ${ouputfiles}
- COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xml2cc_new.pl ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_CURRENT_BINARY_DIR}/params nosubdir
+ COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/xml2cc_new.pl ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_CURRENT_BINARY_DIR}/params nosubdir
DEPENDS ${file}
)
@@ -53,7 +51,6 @@ endforeach()
if ( metview )
-
foreach( file ${metview_xmls} )
get_filename_component( path ${file} PATH )
get_filename_component( basefile ${file} NAME_WE )
@@ -64,7 +61,7 @@ if ( metview )
# generate the code
add_custom_command(
OUTPUT ${metviewfiles}
- COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/xml2mv.pl ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_CURRENT_BINARY_DIR}/params nosubdir
+ COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/xml2mv.pl ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_CURRENT_BINARY_DIR}/params nosubdir
DEPENDS ${file}
)
@@ -75,16 +72,14 @@ if ( metview )
if(qt)
SET(qt_drivers_HEADERS drivers/MgQ/MgQPlotScene.h)
- QT4_WRAP_CPP(qt_drivers_HEADERS_MOC ${qt_drivers_HEADERS})
+ if( MAGICS_QT5 )
+ QT5_WRAP_CPP(qt_drivers_HEADERS_MOC ${qt_drivers_HEADERS})
+ else()
+ QT4_WRAP_CPP(qt_drivers_HEADERS_MOC ${qt_drivers_HEADERS})
+ endif()
list( APPEND drivers_srcs drivers/MgQ/MgQPlotScene.cc ${qt_drivers_HEADERS_MOC})
endif()
-
endif()
-
-
-
-
-
add_custom_target( magics_params DEPENDS ${magics_params_srcs} )
@@ -104,13 +99,13 @@ if( metview )
add_subdirectory( libMagWrapper )
endif()
-if( MAGICS_ODB )
+if( HAVE_ODB )
add_subdirectory( oda )
endif()
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/common )
-ecbuild_add_library( TARGET MagPlusShared
+ecbuild_add_library( TARGET MagPlus
DEPENDS magics_params
SOURCES
magics.h
@@ -129,29 +124,21 @@ ecbuild_add_library( TARGET MagPlusShared
${common_templates}
DEFINITIONS
${MAGICS_EXTRA_DEFINITIONS} MAGICS_EXCEPTION=on
- LIBS
+ LIBS
${MAGICS_EXTRA_LIBRARIES}
- TYPE SHARED
- )
+ TYPE SHARED )
-ecbuild_add_library( TARGET MagPlusSingleShared
- SOURCES MagicsSingle.cc
- LIBS MagPlusShared
- TYPE SHARED)
-
-ecbuild_add_library(TARGET MagPlusDoubleShared
- LIBS MagPlusShared
- SOURCES MagicsDouble.cc
- TYPE SHARED)
+ecbuild_add_library( TARGET MagPlusSingle
+ SOURCES MagicsSingle.cc
+ LIBS MagPlus
+ TYPE SHARED )
-SET_TARGET_PROPERTIES(MagPlusShared PROPERTIES OUTPUT_NAME "MagPlus")
-SET_TARGET_PROPERTIES(MagPlusDoubleShared PROPERTIES OUTPUT_NAME "MagPlusDouble")
-SET_TARGET_PROPERTIES(MagPlusSingleShared PROPERTIES OUTPUT_NAME "MagPlusSingle")
+ecbuild_add_library( TARGET MagPlusDouble
+ SOURCES MagicsDouble.cc
+ LIBS MagPlus
+ TYPE SHARED )
-
-
-
-if ( ENABLE_STATIC_LIBRARY )
+if ( BUILD_SHARED_LIBS STREQUAL "BOTH" )
ecbuild_add_library( TARGET MagPlusStatic
DEPENDS magics_params
SOURCES
@@ -171,23 +158,22 @@ ecbuild_add_library( TARGET MagPlusStatic
${common_templates}
DEFINITIONS
${MAGICS_EXTRA_DEFINITIONS}
- LIBS
+ LIBS
${MAGICS_EXTRA_LIBRARIES}
- TYPE STATIC
- )
-ecbuild_add_library( TARGET MagPlusSingleStatic
- SOURCES MagicsSingle.cc
- INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/common
- TYPE SHARED)
-
-ecbuild_add_library(TARGET MagPlusDoubleStatic
- SOURCES MagicsDouble.cc
- INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/common
- TYPE SHARED)
-
- SET_TARGET_PROPERTIES(MagPlusStatic PROPERTIES OUTPUT_NAME "MagPlus")
- SET_TARGET_PROPERTIES(MagPlusDoubleStatic PROPERTIES OUTPUT_NAME "MagPlusDouble")
- SET_TARGET_PROPERTIES(MagPlusSingleStatic PROPERTIES OUTPUT_NAME "MagPlusSingle")
+ TYPE STATIC
+ OUTPUT_NAME MagPlus )
+
+ecbuild_add_library( TARGET MagPlusSingleStatic
+ SOURCES MagicsSingle.cc
+ LIBS MagPlusStatic
+ TYPE STATIC
+ OUTPUT_NAME MagPlusSingle )
+
+ecbuild_add_library( TARGET MagPlusDoubleStatic
+ SOURCES MagicsDouble.cc
+ LIBS MagPlusStatic
+ TYPE STATIC
+ OUTPUT_NAME MagPlusDouble )
endif()
@@ -205,6 +191,8 @@ if( metview )
${CMAKE_CURRENT_SOURCE_DIR}/terralib/kernel
${CMAKE_CURRENT_SOURCE_DIR}/terralib/utils
${CMAKE_CURRENT_SOURCE_DIR}/libMagWrapper )
+
+
ecbuild_add_library( TARGET MagWrapper
DEPENDS mv_params magics_params
diff --git a/src/basic/BasicGraphicsObject.cc b/src/basic/BasicGraphicsObject.cc
index 7daafc2..201dba0 100644
--- a/src/basic/BasicGraphicsObject.cc
+++ b/src/basic/BasicGraphicsObject.cc
@@ -23,7 +23,6 @@
#include "BaseDriver.h"
using namespace magics;
-
BasicGraphicsObject::BasicGraphicsObject() :
parent_(0)
{
diff --git a/src/basic/BasicGraphicsObject.h b/src/basic/BasicGraphicsObject.h
index 4f563ec..a4f5293 100644
--- a/src/basic/BasicGraphicsObject.h
+++ b/src/basic/BasicGraphicsObject.h
@@ -32,6 +32,7 @@
#include "MagLog.h"
#include "VectorOfPointers.h"
+#include "MagException.h"
namespace magics {
@@ -48,18 +49,18 @@ public:
virtual ~BasicGraphicsObject();
virtual bool reproject(BasicGraphicsObjectContainer&) const
- { MagLog::error() << "BasicGraphicsObject::reproject(...)--->Need to be implemented!\n"; assert(0); return false; }
+ { MagLog::error() << "BasicGraphicsObject::reproject(...)--->Need to be implemented!\n"; ASSERT(0); return false; }
virtual void redisplay(const BaseDriver&) const
{ MagLog::dev() << "BasicGraphicsObject::redisplay(...)--->Not yet implemented\n"; }
void parent(BasicGraphicsObjectContainer* parent)
{
- //assert(parent_ == 0);
+ //ASSERT(parent_ == 0);
parent_ = parent;
}
void check();
- BasicGraphicsObjectContainer& parent() { assert(parent_); return *parent_; }
+ BasicGraphicsObjectContainer& parent() { ASSERT(parent_); return *parent_; }
void makeBrother(const BasicGraphicsObject& brother)
{ parent_ = brother.parent_; }
@@ -136,7 +137,7 @@ public:
double absoluteX() const //absolute position from the root
{
- assert(parent_); return parent_->absoluteX();
+ ASSERT(parent_); return parent_->absoluteX();
}
virtual void getDriverInfo(double& x, double& y, double& width, double& height)
@@ -147,32 +148,32 @@ public:
virtual double absoluteY() const //absolute position from the root
{
- assert(parent_); return parent_->absoluteY();
+ ASSERT(parent_); return parent_->absoluteY();
}
virtual double absoluteWidth() const //absolute position from the root
{
- assert(parent_); return parent_->absoluteWidth();
+ ASSERT(parent_); return parent_->absoluteWidth();
}
virtual double absoluteHeight() const //absolute position from the root
{
- assert(parent_); return parent_->absoluteHeight();
+ ASSERT(parent_); return parent_->absoluteHeight();
}
virtual double absoluteWidth(double width) const //absolute position from the root
{
- assert(parent_); return parent_->absoluteWidth(width);
+ ASSERT(parent_); return parent_->absoluteWidth(width);
}
virtual double absoluteHeight(double height) const //absolute position from the root
{
- assert(parent_); return parent_->absoluteHeight(height);
+ ASSERT(parent_); return parent_->absoluteHeight(height);
}
virtual const Transformation& transformation() const //returns the Transformation
{
- assert(parent_); return parent_->transformation();
+ ASSERT(parent_); return parent_->transformation();
}
const vector<BasicGraphicsObject*>& objects() { //
//first we add
diff --git a/src/basic/BasicSceneObject.cc b/src/basic/BasicSceneObject.cc
index c7bd4ae..3e094fc 100644
--- a/src/basic/BasicSceneObject.cc
+++ b/src/basic/BasicSceneObject.cc
@@ -174,7 +174,7 @@ double BasicSceneNode::absoluteHeight() const
void BasicSceneNode::newpage()
{
- assert(manager_);
+ ASSERT(manager_);
manager_->newpage();
}
diff --git a/src/basic/BasicSceneObject.h b/src/basic/BasicSceneObject.h
index 81b5319..c75b749 100644
--- a/src/basic/BasicSceneObject.h
+++ b/src/basic/BasicSceneObject.h
@@ -58,6 +58,7 @@ class BottomAxisVisitor;
class LeftAxisVisitor;
class RightAxisVisitor;
class BackgroundVisitor;
+class FrameVisitor;
class TextVisitor;
class MetaDataVisitor;
class LegendVisitor;
@@ -96,8 +97,8 @@ public:
bool items_empty() { return items_.empty(); }
- virtual void text(TextVisitor* text) { assert(parent_); parent_->text(text); }
- virtual void legend(LegendVisitor* legend) { assert(parent_); parent_->legend(legend); }
+ virtual void text(TextVisitor* text) { ASSERT(parent_); parent_->text(text); }
+ virtual void legend(LegendVisitor* legend) { ASSERT(parent_); parent_->legend(legend); }
virtual void getReady(const LegendVisitor&);
@@ -118,7 +119,7 @@ public:
}
void orphan() { parent_ = 0; }
- BasicSceneObject& parent() const { assert(parent_); return *parent_; }
+ BasicSceneObject& parent() const { ASSERT(parent_); return *parent_; }
virtual void set(const XmlNode&)
{ MagLog::dev() << "Warning: BasicSceneObject::set(const XmlNode&)-->Not implemented!" << endl; }
virtual void resolve();
@@ -149,6 +150,7 @@ public:
virtual void visit(LeftAxisVisitor& left) { dispatch(left); }
virtual void visit(RightAxisVisitor& right) { dispatch(right); }
virtual void visit(BackgroundVisitor& background) { dispatch(background); }
+ virtual void visit(FrameVisitor& frame) { dispatch(frame); }
virtual void visit(TextVisitor& text) { dispatch(text); }
virtual void visit(LegendVisitor& legend) { dispatch(legend); }
@@ -161,44 +163,44 @@ public:
virtual void execute()
{
- assert(parent_);
+ ASSERT(parent_);
return parent_->execute();
}
virtual BasicGraphicsObject* visualise()
{
- assert(parent_);
+ ASSERT(parent_);
return parent_->visualise();
}
- virtual MagicsMode mode() { assert(parent_); return parent_->mode(); }
+ virtual MagicsMode mode() { ASSERT(parent_); return parent_->mode(); }
virtual Transformation& transformation() const
- { assert(parent_); return parent_->transformation(); }
+ { ASSERT(parent_); return parent_->transformation(); }
virtual const Layout& layout() const
- { assert(parent_); return parent_->layout(); }
+ { ASSERT(parent_); return parent_->layout(); }
virtual BasicGraphicsObject* toDisplay()
- { assert(parent_); return parent_->toDisplay(); }
+ { ASSERT(parent_); return parent_->toDisplay(); }
virtual double absoluteWidth() const
- { assert ( parent_ ); return parent_->absoluteWidth(); }
+ { ASSERT ( parent_ ); return parent_->absoluteWidth(); }
virtual double absoluteHeight() const
- { assert ( parent_ ); return parent_->absoluteHeight(); }
+ { ASSERT ( parent_ ); return parent_->absoluteHeight(); }
virtual void absoluteRootWidth(double width)
- { assert ( parent_ ); return parent_->absoluteRootWidth(width); }
+ { ASSERT ( parent_ ); return parent_->absoluteRootWidth(width); }
virtual void absoluteRootHeight(double height)
- { assert ( parent_ ); return parent_->absoluteRootHeight(height); }
+ { ASSERT ( parent_ ); return parent_->absoluteRootHeight(height); }
virtual int rootWidthResolution() const
- { assert ( parent_ ); return parent_->rootWidthResolution(); }
+ { ASSERT ( parent_ ); return parent_->rootWidthResolution(); }
virtual int rootHeightResolution() const
- { assert ( parent_ ); return parent_->rootHeightResolution(); }
+ { ASSERT ( parent_ ); return parent_->rootHeightResolution(); }
virtual int widthResolution() const
- { assert ( parent_ ); return parent_->rootWidthResolution(); }
+ { ASSERT ( parent_ ); return parent_->rootWidthResolution(); }
virtual int heightResolution() const
- { assert ( parent_ ); return parent_->rootHeightResolution(); }
+ { ASSERT ( parent_ ); return parent_->rootHeightResolution(); }
const string& name() const { return name_; }
void name(const string& name) { name_ = name; }
- virtual BasicSceneNode* insert(BasicPositionalObject*) { assert (false); return 0;}
+ virtual BasicSceneNode* insert(BasicPositionalObject*) { ASSERT (false); return 0;}
protected:
@@ -266,7 +268,7 @@ public:
virtual BasicSceneNode* insert(BasicPositionalObject*); // Return the node tinto which the object has been inserted!
Layout& layout() const
{
- { assert(layout_); return *layout_; }
+ { ASSERT(layout_); return *layout_; }
}
virtual void getReady();
virtual BasicSceneNode* clone();
diff --git a/src/basic/CMakeLists.txt b/src/basic/CMakeLists.txt
index 05b25e3..cbb2b4b 100644
--- a/src/basic/CMakeLists.txt
+++ b/src/basic/CMakeLists.txt
@@ -47,7 +47,7 @@ WebFormat.h
XmlMagics.cc
XmlMagics.h
)
-if ( ENABLE_METVIEW )
+if ( HAVE_METVIEW )
list (APPEND metview_include
basic/MagicsObserver.h
basic/MagicsEvent.h
diff --git a/src/basic/FortranMagics.cc b/src/basic/FortranMagics.cc
index d610de2..9bfe7b0 100644
--- a/src/basic/FortranMagics.cc
+++ b/src/basic/FortranMagics.cc
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file FortranMagics.cc
\brief Implementation of the Template class FortranMagics.
-
+
Magics Team - ECMWF 2007
-
+
Started: Fri 9-Mar-2007
Changes:
-
+
*/
@@ -39,7 +39,7 @@
#include "TextVisitor.h"
#include "LegendVisitor.h"
#include "VisualAction.h"
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
#include "GribDecoder.h"
#endif
#include "MapGenDecoder.h"
@@ -66,11 +66,11 @@
#include "MetaData.h"
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
#include "NetcdfDecoder.h"
#endif
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
#include "ObsDecoder.h"
#endif
@@ -84,21 +84,21 @@ FortranMagics::FortranMagics() : drivers_(0), output_(0), action_(0), empty_(tr
gribindex_(0),legend_todo_(false), symbolinput_todo_ (false), matrixinput_todo_(false), polyinput_todo_(false)
{
- assert (singleton_ == 0);
+ ASSERT (singleton_ == 0);
singleton_ = this;
writeMagLog("fortran");
-}
+}
-FortranMagics::~FortranMagics()
+FortranMagics::~FortranMagics()
{
if ( drivers_ ) delete drivers_;
// if ( root_ ) delete root_;
if ( output_ ) delete output_;
singleton_ = 0;
-
- /*
+
+ /*
ParameterManager::release();
TitleTemplate::release();
@@ -108,7 +108,7 @@ FortranMagics::~FortranMagics()
/*!
Class information are given to the output-stream.
-*/
+*/
void FortranMagics::print(ostream& out) const
{
out << "FortranMagics[";
@@ -127,7 +127,7 @@ void FortranMagics::popen()
MagLog::userInfo() << "\n";
MagLog::userInfo() << " Meteorological Applications Graphics Integrated Colour System\n";
MagLog::userInfo() << "\n";
- MagLog::userInfo() << " Developed By\n";
+ MagLog::userInfo() << " Developed By\n";
MagLog::userInfo() << "\n";
MagLog::userInfo() << " The European Centre for Medium-Range Weather Forecasts\n";
MagLog::userInfo() << "\n";
@@ -136,14 +136,14 @@ void FortranMagics::popen()
MagLog::userInfo() << "------------------------------------------------------------------\n";
}
// actions_.push(&FortranMagics::legend);
- actions_.push(&FortranMagics::subpage);
- actions_.push(&FortranMagics::page);
- actions_.push(&FortranMagics::superpage);
- actions_.push(&FortranMagics::drivers);
+ actions_.push(&FortranMagics::subpage);
+ actions_.push(&FortranMagics::page);
+ actions_.push(&FortranMagics::superpage);
+ actions_.push(&FortranMagics::drivers);
}
/*! \brief Main dispatch method
- Here is where the real magics is happen. Everything is dispatched, followed
+ Here is where the real magics is happen. Everything is dispatched, followed
by a comprehensive clean-up.
*/
void FortranMagics::pclose()
@@ -193,7 +193,7 @@ void FortranMagics::pclose()
stringarray::iterator itend = output_resource_list_.end();
for(; it != itend; it++)
{
- MagLog::userInfo() << " - "<<(*it)<<"\n";
+ MagLog::userInfo() << " - "<<(*it)<<"\n";
}
MagLog::userInfo() << "\n";
*/
@@ -215,7 +215,7 @@ void FortranMagics::drivers()
void FortranMagics::subpage()
{
- axisContainer_ = new FortranViewNode();
+ axisContainer_ = new FortranViewNode();
axisContainer_->push_back(new MetaDataVisitor());
top()->push_back(axisContainer_);
@@ -229,7 +229,7 @@ void FortranMagics::page()
if ( empty() ) return;
while (top() != root_) {
- pop();
+ pop();
if ( empty() ) break;
}
@@ -247,7 +247,7 @@ void FortranMagics::newpage()
{
if ( empty() ) return;
BasicSceneObject* to = top();
-
+
while ( to != root_) {
pop();
to = top();
@@ -275,8 +275,8 @@ void FortranMagics::superpage()
void FortranMagics::simplelegend()
{
- // used fronm the python interface!
- // add a new legend!
+ // used fronm the python interface!
+ // add a new legend!
legends_.clear();
legend();
@@ -285,29 +285,29 @@ void FortranMagics::simplelegend()
void FortranMagics::legend()
{
if ( legends_.empty() == false ) return;
-
+
if (!legend_todo_) return;
legend_todo_ = false;
- string mode;
+ string mode;
ParameterManager::get("legend_box_mode", mode);
-
- if (magCompare(mode, "positional") )
- legends_.push_back(new FortranPositionalLegendVisitor());
- else
- legends_.push_back(new FortranAutomaticLegendVisitor());
+
+ if (magCompare(mode, "positional") )
+ legends_.push_back(new FortranPositionalLegendVisitor());
+ else
+ legends_.push_back(new FortranAutomaticLegendVisitor());
}
void FortranMagics::plegend()
-{
+{
legend_todo_ = true;
legends_.clear();
actions_.push(&FortranMagics::legend);
}
void FortranMagics::poverlay()
-{
+{
actions();
@@ -339,7 +339,7 @@ void FortranMagics::pnew(const string& type)
finish();
pop();
actions_.push(&FortranMagics::legend);
- actions_.push(&FortranMagics::subpage);
+ actions_.push(&FortranMagics::subpage);
}
if ( magCompare(type, "page") )
{
@@ -348,8 +348,8 @@ void FortranMagics::pnew(const string& type)
dispatch();
empty_ = true;
pop();
- actions_.push(&FortranMagics::legend);
- actions_.push(&FortranMagics::subpage);
+ actions_.push(&FortranMagics::legend);
+ actions_.push(&FortranMagics::subpage);
actions_.push(&FortranMagics::page);
}
@@ -363,16 +363,16 @@ void FortranMagics::pnew(const string& type)
dispatch();
empty_ = true;
actions_.push(&FortranMagics::legend);
- actions_.push(&FortranMagics::subpage);
- actions_.push(&FortranMagics::page);
+ actions_.push(&FortranMagics::subpage);
+ actions_.push(&FortranMagics::page);
actions_.push(&FortranMagics::newpage);
}
- // WE reset !
+ // WE reset !
axisContainer_ = 0;
action_ = 0;
-
+
string legend;
ParameterManager::get("legend", legend);
legend_todo_ = magCompare(legend, "on");
@@ -387,7 +387,7 @@ void FortranMagics::actions()
Action action = actions_.top();
(this->*action)();
actions_.pop();
- empty_ = false;
+ empty_ = false;
}
}
@@ -402,7 +402,7 @@ void FortranMagics::pcoast()
void FortranMagics::ptaylor()
{
- actions();
+ actions();
TaylorGrid* taylor = new TaylorGrid();
top()->push_back(taylor);
@@ -418,7 +418,7 @@ void FortranMagics::ptephi()
void FortranMagics::pobs()
{
actions();
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
action_ = new VisualAction();
ObsDecoder* obs = new ObsDecoder();
if ( obs->defined() ) {
@@ -452,22 +452,22 @@ void FortranMagics::ptest()
/*! \brief Finish plot by checking axis, legend and texts
- *
+ *
*/
void FortranMagics::finish()
{
if ( !empty_ ) {
- actions(); // The flag to force the generation of the plot has been set!
+ actions(); // The flag to force the generation of the plot has been set!
while ( !axis_.empty() )
{
axisContainer_->push_back(axis_.top());
axis_.pop();
}
}
-
+
if ( !axisContainer_ ) return;
- // check if we have to add a legend!
- if ( !legends_.empty() && axisContainer_ && !axisContainer_->items_empty() )
+ // check if we have to add a legend!
+ if ( !legends_.empty() && axisContainer_ && !axisContainer_->items_empty() )
{
legend();
for (vector<LegendVisitor* >::iterator legend = legends_.begin(); legend != legends_.end(); ++legend)
@@ -477,13 +477,13 @@ void FortranMagics::finish()
legends_.clear();
}
- // Check any text
+ // Check any text
for (vector<BasicSceneObject* >::iterator other = later_.begin(); other != later_.end(); ++other)
{
top()->push_back(*other);
}
later_.clear();
-
+
for (vector<FortranTextVisitor* >::iterator text = texts_.begin(); text != texts_.end(); ++text)
{
top()->text(*text);
@@ -516,18 +516,18 @@ void FortranMagics::pmapgen()
}
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
void FortranMagics::pgrib()
{
actions();
action_ = new VisualAction();
static string gribfile;
-
+
string grib;
ParameterManager::get("grib_input_file_name", grib);
int index;
ParameterManager::get("grib_field_position", index);
-
+
if ( grib == gribfile )
{
@@ -546,7 +546,7 @@ void FortranMagics::pgrib()
gribfile = grib;
gribindex_ = index;
}
-
+
action_->data(new GribDecoder());
top()->push_back(action_);
}
@@ -576,7 +576,7 @@ void FortranMagics::pgeo()
void FortranMagics::pnetcdf()
{
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
actions();
action_ = new VisualAction();
@@ -610,13 +610,13 @@ void FortranMagics::ptable()
}
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
#include "OdaDecoder.h"
#endif
void FortranMagics::podb()
{
actions();
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
action_ = new VisualAction();
@@ -629,7 +629,7 @@ void FortranMagics::podb()
void FortranMagics::data(Data* data)
{
- assert ( action_ == 0);
+ ASSERT ( action_ == 0);
action_ = new VisualAction();
action_->data(data);
top()->push_back(action_);
@@ -669,20 +669,20 @@ void split(VisualAction& action) {
ParameterManager::get("contour_min_level", min);
// set the below contour
ParameterManager::set("contour_max_level", level);
-
+
LineStyle style, highlightstyle;
double thickness, highlightthickness;
string colour, highlightcolour;
-
+
param("contour_below_line_style", "contour_line_style", style);
param("contour_below_line_thickness", "contour_line_thickness", thickness);
param("contour_below_line_colour", "contour_line_colour", colour);
param("contour_below_highlight_style", "contour_highlight_line_style", highlightstyle);
param("contour_below_highlight_thickness", "contour_highlight_line_thickness", highlightthickness);
param("contour_below_highlight_colour", "contour_highlight_line_colour",highlightcolour);
-
+
action.visdef(new Contour());
-
+
// set the above contour
ParameterManager::set("contour_max_level", max);
ParameterManager::set("contour_min_level", level);
@@ -693,19 +693,19 @@ void split(VisualAction& action) {
param("contour_above_highlight_thickness", "contour_highlight_line_thickness", thickness);
param("contour_above_highlight_colour", "contour_highlight_line_colour", colour);
action.visdef(new Contour());
- // Should we reset???
+ // Should we reset???
}
else { */
action.visdef(new Contour());
// }
}
-
+
void FortranMagics::pcont()
{
- // First check any split contour! I hate it!
+ // First check any split contour! I hate it!
Timer timer("pcont", "setting");
- actions();
+ actions();
if ( !action_ || matrixinput_todo_ )
{
@@ -716,7 +716,7 @@ void FortranMagics::pcont()
action_->data(input);
else {
delete input;
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
// Sylvie: Is this causing GribDecoder MagExceptions when matrx input is faulty?
action_->data(new GribDecoder());
#else
@@ -733,7 +733,7 @@ void FortranMagics::pcont()
void FortranMagics::pwind()
{
- actions();
+ actions();
if ( matrixinput_todo_ ) {
action_ = 0;
}
@@ -742,11 +742,11 @@ void FortranMagics::pwind()
action_ = new VisualAction();
InputMatrix* input = new InputMatrix();
matrixinput_todo_ = false;
- if (input->defined() )
+ if (input->defined() )
action_->data(input);
else {
delete input;
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
// Sylvie: Is this causing GribDecoder MagExceptions when matrx input is faulty?
GribDecoder* grib = new GribDecoder();
grib->dimension(2);
@@ -770,22 +770,22 @@ void FortranMagics::ptext()
{
string mode;
ParameterManager::get("text_mode", mode);
-
+
FortranTextVisitor* node;
- if ( magCompare(mode, "positional") )
- node = new FortranPositionalTextVisitor();
- else
- node = new FortranAutomaticTextVisitor();
-
+ if ( magCompare(mode, "positional") )
+ node = new FortranPositionalTextVisitor();
+ else
+ node = new FortranAutomaticTextVisitor();
+
texts_.push_back(node);
empty_ = false;
}
-
+
void FortranMagics::psymb()
{
- actions();
-
+ actions();
+
string mode;
string wind;
ParameterManager::get("symbol_position_mode", mode);
@@ -836,18 +836,34 @@ void FortranMagics::pline()
actions();
- action_ = new VisualAction();
- polyinput_todo_ = false;
- SimplePolylineInput* input = new SimplePolylineInput();
- top()->push_back(action_);
- action_->data(input);
+ if ( !action_ ) {
+ action_ = new VisualAction();
+
+ polyinput_todo_ = false;
+ SimplePolylineInput* input = new SimplePolylineInput();
+ top()->push_back(action_);
+ action_->data(input);
+ }
action_->visdef(new SimplePolylineVisualiser());
}
+#include "GeoJSon.h"
+void FortranMagics::geojson()
+{
+ actions();
+
+
+ action_ = new VisualAction();
+
+ GeoJSon* geo = new GeoJSon();
+
+ top()->push_back(action_);
+ action_->data(geo);
+}
#include "WrepJSon.h"
#include "EpsXmlInput.h"
#include "EpsGraph.h"
@@ -864,6 +880,7 @@ void FortranMagics::wrepjson()
action_->data(wrep);
}
+
void FortranMagics::epsinput()
{
actions();
@@ -954,15 +971,15 @@ void FortranMagics::paxis()
{
try {
string orientation;
-
- ParameterManager::get("axis_orientation", orientation);
-//
+
+ ParameterManager::get("axis_orientation", orientation);
+//
if (magCompare(orientation, "vertical") ) {
- Axis* vaxis = new VerticalAxis();
+ Axis* vaxis = new VerticalAxis();
MagLog::dev() << *vaxis << "\n";
axis_.push(vaxis);
- }
- else {
+ }
+ else {
Axis* haxis = new HorizontalAxis();
MagLog::dev() << *haxis << "\n";
axis_.push(haxis);
@@ -1012,14 +1029,14 @@ void FortranMagics::pgraph()
void FortranMagics::pboxplot()
{
actions();
-
+
action_ = new VisualAction();
-
+
BoxPlotDecoder* input = new BoxPlotDecoder();
BoxPlotVisualiser* plot = new BoxPlotVisualiser();
top()->push_back(action_);
action_->data(input);
- MagLog::dev() << *input << "\n";
+ MagLog::dev() << *input << "\n";
action_->visdef(plot);
}
diff --git a/src/basic/FortranMagics.h b/src/basic/FortranMagics.h
index 9d6da2c..41c0a3a 100644
--- a/src/basic/FortranMagics.h
+++ b/src/basic/FortranMagics.h
@@ -79,7 +79,7 @@ public:
void podb();
void plegend();
void simplelegend();
-
+ void geojson();
//Wrep-Eps family!
void epsinput();
void wrepjson();
diff --git a/src/basic/Layer.cc b/src/basic/Layer.cc
index d26764c..cbc6371 100644
--- a/src/basic/Layer.cc
+++ b/src/basic/Layer.cc
@@ -63,7 +63,7 @@ Layer::~Layer()
void Layer::execute(int , const BaseDriver&, const Layout&) const
{
- assert(false);
+ ASSERT(false);
}
void Layer::getReady(int) const
@@ -243,7 +243,7 @@ void SingleLayer::execute(const BaseDriver& driver) const
if ( !parentLayer_->visibility() )
return;
- assert(objects_);
+ ASSERT(objects_);
objects_->redisplay(driver);
}
@@ -256,7 +256,7 @@ void SingleLayer::release()
void SingleLayer::update(const Layout& parent)
{
- assert(objects_);
+ ASSERT(objects_);
objects_->width(parent.width());
objects_->height(parent.height());
objects_->x(parent.x());
@@ -268,7 +268,7 @@ void SingleLayer::getReady() const
if ( !parentLayer_->visibility() )
return;
if ( parentLayer_->parent()->state() == geometry_changed) {
- assert(objects_);
+ ASSERT(objects_);
objects_->clear();
}
if ( !objects_ ) {
@@ -735,7 +735,7 @@ vector<Layer*>& SceneLayer::prepare(int i) const
map<int, vector<Layer*> >::iterator step = steps_.find(i);
if ( step != steps_.end() )
return step->second;
- assert(rules_);
+ ASSERT(rules_);
steps_.insert(make_pair(i, vector<Layer*>()));
if ( i >= (int)(*rules_).size() )
{
@@ -820,7 +820,7 @@ void SceneLayer::execute(Layer* stepLayer, int i, const BaseDriver& out) const
// Look for the step!
- assert(rules_);
+ ASSERT(rules_);
if ( rules_->size() > i ) {
AnimationStep* step = (*rules_)[i];
map<Layer*, int>::iterator l = step->find(stepLayer);
@@ -830,7 +830,7 @@ void SceneLayer::execute(Layer* stepLayer, int i, const BaseDriver& out) const
stepLayer->getInfo(i, out);
}
else {
- assert(false);
+ ASSERT(false);
//stepLayer->execute(i, driver);
}
}
@@ -851,7 +851,7 @@ Layer* SceneLayer::findLayer(Layer* stepLayer,int i) const
return 0;
// Look for the step!
- assert(rules_);
+ ASSERT(rules_);
//Temporary fix!!
if(i >= rules_->size())
@@ -891,7 +891,7 @@ void SceneLayer::getReady(int i ) const
}
}
else {
- assert(rules_);
+ ASSERT(rules_);
AnimationStep* step = (*rules_)[i];
for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
@@ -953,7 +953,7 @@ void SceneLayer::executeInfo(int i, const BaseDriver&) const
}
else {
- assert(rules_);
+ ASSERT(rules_);
if ( rules_->size() > 0 ) {
AnimationStep* step = (*rules_)[i];
@@ -1001,7 +1001,7 @@ void SceneLayer::executeInfo(int i, const BaseDriver&) const
void MagnifierCollector::visit(const BaseDriver& driver)
{
- assert(layout_);
+ ASSERT(layout_);
Symbol* points = new Symbol();
points->setSymbol("magics_3"); // A little dot
diff --git a/src/basic/Layer.h b/src/basic/Layer.h
index 58884eb..c45d8a1 100644
--- a/src/basic/Layer.h
+++ b/src/basic/Layer.h
@@ -319,7 +319,7 @@ public:
void redisplay(const BaseDriver& driver) const;
void redisplayAll(const BaseDriver& driver) const;
void add(Layer*);
- Layout* layoutPtr() { assert (layout_); return layout_; }
+ Layout* layoutPtr() { ASSERT (layout_); return layout_; }
BasicGraphicsObjectContainer* parent() { return parent_; }
void addVisitor(LayoutVisitor* visitor) { visitors_.insert(visitor); }
void setMagicsMode(MagicsMode mode) { mode_ = mode; }
diff --git a/src/basic/LegendVisitor.cc b/src/basic/LegendVisitor.cc
index bda116f..090b6df 100644
--- a/src/basic/LegendVisitor.cc
+++ b/src/basic/LegendVisitor.cc
@@ -59,6 +59,7 @@ LegendVisitor::LegendVisitor()
view_y_ = 5;
view_width_ = 90;
view_height_=90;
+ positional_ = false;
}
@@ -218,6 +219,7 @@ void LegendVisitor::build()
MagFont font(font_, font_style_, font_size_);
font.colour(*colour_);
(*entry)->font(font);
+ (*entry)->factor(symbol_factor_);
(*entry)->angle((orientation_/180.)*3.14);
(*entry)->borderColour(entry_border_ ? *entry_border_colour_ : Colour("automatic"));
@@ -1146,7 +1148,7 @@ void LegendVisitor::getReady()
void XmlLegendVisitor::getReady()
{
- assert(BasicSceneObject::parent_);
+ ASSERT(BasicSceneObject::parent_);
Dimension bottom(bottom_, BasicSceneObject::parent_->absoluteWidth(), 0);
Dimension left(left_, BasicSceneObject::parent_->absoluteHeight(), 0);
@@ -1250,6 +1252,8 @@ void LegendEntry::set(const LegendVisitor& attributes)
void SimpleSymbolEntry::set(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
+ symbol_->setHeight(symbol_->getHeight()*factor_);
+
symbol_->push_back(centreSymbolBox(point));
legend.push_back(symbol_);
}
@@ -1277,6 +1281,7 @@ const string& LegendEntry::label() const
}
void SimpleSymbolEntry::rowBox(const PaperPoint& point, BasicGraphicsObjectContainer& legend)
{
+
Polyline* box = new Polyline();
FillShadingProperties* shading = new FillShadingProperties();
box->setFillColour(colour());
diff --git a/src/basic/LegendVisitor.h b/src/basic/LegendVisitor.h
index 3ac0758..165dcc5 100644
--- a/src/basic/LegendVisitor.h
+++ b/src/basic/LegendVisitor.h
@@ -88,6 +88,7 @@ public:
void first() { first_ = true; }
void notext() { text_ = false; }
void text() { text_ = true; }
+ void factor(double factor) { factor_ = factor; }
void width(double width) { width_ = width; }
PaperPoint centreSymbolBox(const PaperPoint&);
@@ -121,6 +122,7 @@ protected:
MagFont font_;
double angle_;
double width_;
+ double factor_;
int population_;
int totalPopulation_;
@@ -316,10 +318,10 @@ public:
LegendVisitor();
virtual ~LegendVisitor();
virtual void getReady();
- virtual LegendVisitor* clone() { assert(false); return 0; }
- virtual Layout& layout() const { assert( layout_); return *layout_; }
- virtual Layout* layoutPtr() const { assert( layout_); return layout_; }
- //virtual Layout* legend() { assert( layout_); return this; }
+ virtual LegendVisitor* clone() { NOTIMP; return 0; }
+ virtual Layout& layout() const { ASSERT( layout_); return *layout_; }
+ virtual Layout* layoutPtr() const { ASSERT( layout_); return layout_; }
+ //virtual Layout* legend() { ASSERT( layout_); return this; }
void set(const XmlNode& node) { LegendVisitorAttributes::set(node); }
void add(LegendEntry* entry) { VectorOfPointers<vector<LegendEntry*> >::push_back(entry); }
diff --git a/src/basic/MagnifierVisitor.cc b/src/basic/MagnifierVisitor.cc
index 07636fb..358a8ff 100644
--- a/src/basic/MagnifierVisitor.cc
+++ b/src/basic/MagnifierVisitor.cc
@@ -118,7 +118,7 @@ void MagnifierVisitor::redisplay(const BaseDriver& driver, vector<PaperPoint>& p
// Update the view from the transfomation
// visit the owner to get the info!
- assert(owner_);
+ ASSERT(owner_);
double xmin = pp.front().x();
double xmax = pp.front().x();
double ymin = pp.front().y();
diff --git a/src/basic/MultiVisdef.cc b/src/basic/MultiVisdef.cc
index c91eb86..1e01106 100644
--- a/src/basic/MultiVisdef.cc
+++ b/src/basic/MultiVisdef.cc
@@ -89,7 +89,7 @@ void MultiVisdef::visit(TopAxisVisitor& top)
void MultiVisdef::visit(Transformation&, Data&)
{
- assert(false);
+ ASSERT(false);
}
void MultiVisdef::visit(Layer& layer)
diff --git a/src/basic/RootSceneNode.cc b/src/basic/RootSceneNode.cc
index 1d7c9c6..7a79aae 100644
--- a/src/basic/RootSceneNode.cc
+++ b/src/basic/RootSceneNode.cc
@@ -375,7 +375,7 @@ BasicSceneNode* RootSceneNode::insert(BasicPositionalObject* node)
BasicSceneNode* RootScenePage::newNode(BasicPositionalObject* node)
{
- assert(root_);
+ ASSERT(root_);
RootScenePage* page = newPage();
page->manager_ = manager_->clone();
@@ -452,7 +452,7 @@ void RootScenePage::resize(double width, double height)
{
width_ = width;
height_ = height;
- assert(layout_);
+ ASSERT(layout_);
layout_->resize(width, height);
}
diff --git a/src/basic/SceneNode.cc b/src/basic/SceneNode.cc
index 7651953..1f6676e 100644
--- a/src/basic/SceneNode.cc
+++ b/src/basic/SceneNode.cc
@@ -128,6 +128,7 @@ void FortranSceneNode::visit(BasicGraphicsObjectContainer& tree)
layout_->push_back(sceneLayer_);
page_id_->visit(*layout_);
layout_->id(iconId_); // For Metview
+ layout_->frameIt();
}
#ifdef MAG_NEXT
else
@@ -147,7 +148,7 @@ void FortranSceneNode::visit(BasicGraphicsObjectContainer& tree)
void FortranSceneNode::getReady()
{
- assert(parent_);
+ ASSERT(parent_);
// Make sure that the dimensions are not bigger that the paper size!
@@ -213,7 +214,7 @@ void XmlSceneNode::getReady()
MagLog::dev() << " SceneNode::getReady() \n";
MagLog::dev() << "XmlSceneNode::getReady() \n";
- assert (parent_);
+ ASSERT (parent_);
Dimension bottom(bottom_, parent_->absoluteWidth(), 0);
Dimension left(left_, parent_->absoluteHeight(), 0);
Dimension width(width_, parent_->absoluteWidth(), 100);
diff --git a/src/basic/SceneVisitor.cc b/src/basic/SceneVisitor.cc
index 6defa38..4022efd 100644
--- a/src/basic/SceneVisitor.cc
+++ b/src/basic/SceneVisitor.cc
@@ -74,7 +74,15 @@ HorizontalAxisVisitor::HorizontalAxisVisitor(const DrawingVisitor&)
HorizontalAxisVisitor::~HorizontalAxisVisitor()
{
}
+FrameVisitor::FrameVisitor()
+{
+ layout_ = new Layout();
+ layout_->name("frame");
+}
+FrameVisitor::~FrameVisitor()
+{
+}
VerticalAxisVisitor::VerticalAxisVisitor(const DrawingVisitor&)
{
}
@@ -290,7 +298,7 @@ double TopAxisVisitor::offsetTip()
void BottomAxisVisitor::tick(double& y1, double& y2, bool out )
{
- assert(current_);
+ ASSERT(current_);
double length = ((current_->ymax_ - current_->ymin_)/current_->absoluteHeight()) * 0.15;
y2 = current_->ymax_;
y1 = (out) ? y2 - length : y2 + length;
@@ -340,7 +348,7 @@ double BottomAxisVisitor::offsetTip()
void LayoutVisitor::push_back(BasicGraphicsObject* object)
{
- assert(current_);
+ ASSERT(current_);
current_->push_back(object);
}
void DrawingVisitor::set(MagnifierCollector& magnifier)
@@ -353,8 +361,8 @@ void DrawingVisitor::set(MagnifierCollector& magnifier)
void LayoutVisitor::newLayout() const { current_ = layout_->clone(); }
Layout& LayoutVisitor::layout() const { if ( !current_ ) newLayout(); return *current_; }
-Layout* LayoutVisitor::layoutPtr() const { assert(layout_); return current_; }
-Layout* LayoutVisitor::mainLayout() const { assert(layout_); return layout_; }
+Layout* LayoutVisitor::layoutPtr() const { ASSERT(layout_); return current_; }
+Layout* LayoutVisitor::mainLayout() const { ASSERT(layout_); return layout_; }
Justification TopAxisVisitor::justificationTickLabel(const string& orientation)
{
diff --git a/src/basic/SceneVisitor.h b/src/basic/SceneVisitor.h
index 38c1ef6..8e3428b 100644
--- a/src/basic/SceneVisitor.h
+++ b/src/basic/SceneVisitor.h
@@ -65,43 +65,44 @@ public:
const Transformation& transformation() const {
- assert(layout_);
+ ASSERT(layout_);
return layout_->transformation();
}
void push_back(BasicGraphicsObject* object);
void parent(BasicGraphicsObjectContainer* parent)
- { assert(layout_); layout_->parent(parent); }
+ { ASSERT(layout_); layout_->parent(parent); }
double minX() const
- { assert(layout_); return layout_->minX(); }
+ { ASSERT(layout_); return layout_->minX(); }
double maxX() const
- { assert(layout_); return layout_->maxX(); }
+ { ASSERT(layout_); return layout_->maxX(); }
double minY() const
- { assert(layout_); return layout_->minY(); }
+ { ASSERT(layout_); return layout_->minY(); }
double maxY() const
- { assert(layout_); return layout_->maxY(); }
+ { ASSERT(layout_); return layout_->maxY(); }
void width(double width)
- { assert(layout_); return layout_->width(width); }
+ { ASSERT(layout_); return layout_->width(width); }
void height(double height)
- { assert(layout_); return layout_->height(height); }
+ { ASSERT(layout_); return layout_->height(height); }
void widthResolution(double width)
- { assert(layout_); return layout_->widthResolution(width); }
+ { ASSERT(layout_); return layout_->widthResolution(width); }
void heightResolution(double height)
- { assert(layout_); return layout_->heightResolution(height); }
+ { ASSERT(layout_); return layout_->heightResolution(height); }
void x(double x)
- { assert(layout_); return layout_->x(x); }
+ { ASSERT(layout_); return layout_->x(x); }
void y(double y)
- { assert(layout_); return layout_->y(y); }
+ { ASSERT(layout_); return layout_->y(y); }
void transformation(Layout& layout) const
{ layout.transformation(layout_->transformation_); }
void transformation(Transformation* transformation)
- { assert(layout_); return layout_->transformation(transformation); }
- void id(const string& id) { assert(layout_); return layout_->id(id); }
- void zoomable(bool zoomable) { assert(layout_); return layout_->zoomable(zoomable); }
- void zoomLevels(int zl) { assert(layout_); return layout_->zoomLevels(zl); }
- void zoomCurrentLevel(int level) { assert(layout_); return layout_->zoomCurrentLevel(level); }
- void frameIt() { assert(layout_); return layout_->frameIt(); }
- void frame(Layout& layout) { assert(layout_); layout_->frame(layout); }
+ { ASSERT(layout_); return layout_->transformation(transformation); }
+ void id(const string& id) { ASSERT(layout_); return layout_->id(id); }
+ void zoomable(bool zoomable) { ASSERT(layout_); return layout_->zoomable(zoomable); }
+ void zoomLevels(int zl) { ASSERT(layout_); return layout_->zoomLevels(zl); }
+ void zoomCurrentLevel(int level) { ASSERT(layout_); return layout_->zoomCurrentLevel(level); }
+ void frameIt() { ASSERT(layout_); return layout_->frameIt(); }
+ void frame(Layout& layout) { ASSERT(layout_); layout_->frame(layout); }
+ void clippIt(bool clip) { ASSERT(layout_); layout_->clippIt(clip); }
protected:
void print(ostream&) const;
Layout* layout_;
@@ -122,8 +123,16 @@ public:
protected:
};
+class FrameVisitor: public LayoutVisitor
+{
+public:
+ FrameVisitor();
+ ~FrameVisitor();
+ void visit(BasicSceneObject& object) { object.visit(*this); }
+};
+
class HorizontalAxisVisitor: public LayoutVisitor
{
public:
diff --git a/src/basic/TagHandler.cc b/src/basic/TagHandler.cc
index 7561e9b..978b082 100644
--- a/src/basic/TagHandler.cc
+++ b/src/basic/TagHandler.cc
@@ -349,6 +349,7 @@ void TagConverter::check(const string& text) {
TagConverter converter(owner_);
converter.font(font_);
converter.decode(text, text_);
+ label_ = text;
}
@@ -418,7 +419,7 @@ void TagConverter::decode(const string& line, Text* text)
tree.visit(*this);
else {
- label_ += line;
+ //label_ += line;
text_->addText(line, font_);
}
if (automatic_ == 0 ) {
diff --git a/src/basic/TextVisitor.cc b/src/basic/TextVisitor.cc
index 88c48d9..819be60 100644
--- a/src/basic/TextVisitor.cc
+++ b/src/basic/TextVisitor.cc
@@ -102,7 +102,10 @@ void TextVisitor::getReady()
void TextVisitor::visit(MetaDataVisitor& meta){
- meta.add("magics.title", "\"" + label_ + "\"");
+ //meta.add("magics.title", "\"" + label_ + "\"");
+
+
+
}
@@ -132,6 +135,7 @@ void TextVisitor::visit() {
Text* text = new Text();
converter.decode(*line, text);
+ label_ = label_ + *line + "<br/>";
currentTexts_[*line].push_back(text);
}
}
@@ -207,11 +211,14 @@ void TextVisitor::visit(BasicSceneObject& parent)
for (vector<TextEntry* >::reverse_iterator entry = key->second.rbegin(); entry != key->second.rend(); ++entry) {
Text* text = new Text();
+
converter.decode((*entry)->entry_, text);
if (text->noText()) {
delete text;
continue;
}
+
+ label_ = label_ + converter.label() + "<br/>";
if ( currentTexts_.find(*line) == currentTexts_.end() )
currentTexts_[*line] = vector<Text*>();
currentTexts_[*line].push_back(text);
@@ -384,7 +391,7 @@ void XmlTextVisitor::set(const XmlNode& node)
void XmlTextVisitor::getReady()
{
- assert (BasicSceneObject::parent_);
+ ASSERT (BasicSceneObject::parent_);
Dimension bottom(bottom_, BasicSceneObject::parent_->absoluteWidth(), 0);
Dimension left(left_, BasicSceneObject::parent_->absoluteHeight(), 0);
diff --git a/src/basic/ViewNode.cc b/src/basic/ViewNode.cc
index 1e798fd..8693db0 100644
--- a/src/basic/ViewNode.cc
+++ b/src/basic/ViewNode.cc
@@ -133,7 +133,6 @@ void ViewNode::visit(HistoVisitor& histo)
-
void ViewNode::prepareLayout(SceneLayer& tree)
{
@@ -141,7 +140,7 @@ void ViewNode::prepareLayout(SceneLayer& tree)
LayoutHelper helper;
components_.clear();
drawing_= new DrawingVisitor();
-
+ frameHelper_= new FrameVisitor();
const double width = 100-drawing_left_-drawing_right_;
const double height = 100-drawing_top_-drawing_bottom_;
double vaxis = 100/absoluteWidth() *vaxis_;
@@ -151,19 +150,36 @@ void ViewNode::prepareLayout(SceneLayer& tree)
}
drawing_->transformation(viewTransformation_);
- drawing_->y(drawing_bottom_);
- drawing_->x(drawing_left_);
- drawing_->height(height);
- drawing_->width(width);
- drawing_->id(id_);
- drawing_->widthResolution(widthResolution()*width/100);
- drawing_->heightResolution(heightResolution()*width/100);
- drawing_->zoomable(true);
- drawing_->zoomLevels(zoomLevels_);
- drawing_->zoomCurrentLevel(zoomCurrentLevel_);
- drawing_->frame(*layout_);
- drawing_->frameIt();
+ drawing_->y(drawing_bottom_);
+ drawing_->x(drawing_left_);
+ drawing_->height(height);
+ drawing_->width(width);
+ drawing_->id(id_);
+ drawing_->widthResolution(widthResolution()*width/100);
+ drawing_->heightResolution(heightResolution()*width/100);
+ drawing_->zoomable(true);
+ drawing_->zoomLevels(zoomLevels_);
+ drawing_->zoomCurrentLevel(zoomCurrentLevel_);
+ drawing_->frame(*layout_);
+ drawing_->frameIt();
+ drawing_->clippIt(layout_->clipp());
+
+
+ frameHelper_->transformation(viewTransformation_);
+ frameHelper_->y(drawing_bottom_);
+ frameHelper_->x(drawing_left_);
+ frameHelper_->height(height);
+ frameHelper_->width(width);
+ frameHelper_->widthResolution(widthResolution()*width/100);
+ frameHelper_->heightResolution(heightResolution()*width/100);
+
+ frameHelper_->frame(*layout_);
+ frameHelper_->frameIt();
+ frameHelper_->clippIt(false);
+
+
components_.push_back(drawing_);
+ components_.push_back(frameHelper_);
helper.add(drawing_);
// Then the axis!
@@ -298,9 +314,9 @@ void ViewNode::visit(SceneLayer& tree)
for ( vector<BasicSceneObject*>::iterator item = items_.begin(); item != items_.end(); ++item) {
(*item)->visit(tree, components_);
}
- if ( drawing_->layoutPtr() )
+ if ( frameHelper_->layoutPtr() )
{
- drawing_->layout().frameIt();
+ frameHelper_->layout().frameIt();
}
if( mode() == interactif )
@@ -356,7 +372,7 @@ XmlViewNode::~XmlViewNode()
void XmlViewNode::getReady()
{
- assert (parent_);
+ ASSERT (parent_);
viewTransformation_ = XmlViewNodeAttributes::transformation_.get();
Dimension bottom(bottom_, parent_->absoluteHeight(), 0);
@@ -540,7 +556,7 @@ protected:
void FortranViewNode::getReady()
{
- assert (parent_);
+ ASSERT (parent_);
viewTransformation_ = FortranViewNodeAttributes::transformation_.get();
viewTransformation_->setDefinition(json_);
@@ -598,6 +614,7 @@ void FortranViewNode::getReady()
ParameterManager::set("subpage_y_position_internal", absy);
layout_->frame(true, frame_, *frame_colour_, frame_line_style_, frame_thickness_);
+ layout_->clippIt(clipping_);
BasicSceneObject::getReady();
}
diff --git a/src/basic/ViewNode.h b/src/basic/ViewNode.h
index a0f6b1b..ecc4936 100644
--- a/src/basic/ViewNode.h
+++ b/src/basic/ViewNode.h
@@ -51,7 +51,7 @@ public:
virtual ~ViewNode();
void setInteractiveInfo(const string& id, int levels, int level) {
name(id);
- assert(layout_);
+ ASSERT(layout_);
layout_->id(id);
id_ = id;
zoomLevels_ = levels;
@@ -85,7 +85,7 @@ protected:
virtual void copy(const ViewNode&);
- Transformation& transformation() const { assert(viewTransformation_); return *viewTransformation_; }
+ Transformation& transformation() const { ASSERT(viewTransformation_); return *viewTransformation_; }
Transformation* viewTransformation_;
@@ -97,17 +97,18 @@ protected:
string animation_;
DrawingVisitor* drawing_;
- TopAxisVisitor* topAxis_;
- BottomAxisVisitor* bottomAxis_;
+ FrameVisitor* frameHelper_;
+ TopAxisVisitor* topAxis_;
+ BottomAxisVisitor* bottomAxis_;
LeftAxisVisitor* leftAxis_;
RightAxisVisitor* rightAxis_;
double vaxis_;
double haxis_;
-
- AnimationRules* rules_;
+
+ AnimationRules* rules_;
LegendVisitor* legend_;
- vector<TextVisitor*> texts_;
+ vector<TextVisitor*> texts_;
vector<LayoutVisitor*> components_;
diff --git a/src/basic/Visdef.h b/src/basic/Visdef.h
index e8b8271..84936a5 100644
--- a/src/basic/Visdef.h
+++ b/src/basic/Visdef.h
@@ -62,7 +62,7 @@ public:
virtual void visit(TopAxisVisitor&) {}
virtual void visit(Transformation&, Data&) {}
virtual void visit(Layer& layer) { MetviewIcon::visit(layer); }
- virtual void beanInfo(IntervalMap<Colour>&) { assert(false); }
+ virtual void beanInfo(IntervalMap<Colour>&) { NOTIMP; }
virtual bool needLegend() { return false; }
virtual void getReady(const LegendVisitor& legend) { legendOnly_ = legend.only_; }
protected:
diff --git a/src/basic/VisualAction.cc b/src/basic/VisualAction.cc
index ac5957e..f703deb 100644
--- a/src/basic/VisualAction.cc
+++ b/src/basic/VisualAction.cc
@@ -303,7 +303,7 @@ void VisualAnimation::visit(AnimationRules& rules)
void VisualAnimation::visit(Transformation& transformation)
{
- assert(loop_);
+ ASSERT(loop_);
loop_->visit(transformation);
}
diff --git a/src/basic/VisualAction.h b/src/basic/VisualAction.h
index a379d3f..c5fe22e 100644
--- a/src/basic/VisualAction.h
+++ b/src/basic/VisualAction.h
@@ -112,7 +112,7 @@ public:
VisualAnimation();
virtual ~VisualAnimation();
void loop(DataLoop* data) { loop_ = data; }
- DataLoop& loop() { assert(loop_); return *loop_; }
+ DataLoop& loop() { ASSERT(loop_); return *loop_; }
protected:
diff --git a/src/basic/XmlMagics.cc b/src/basic/XmlMagics.cc
index 2a56af3..918c853 100644
--- a/src/basic/XmlMagics.cc
+++ b/src/basic/XmlMagics.cc
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -38,7 +38,7 @@
#include "BinaryObject.h"
#include "TephiGrid.h"
#include "TaylorGrid.h"
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
#include "GribDecoder.h"
#endif
#include "TableDecoder.h"
@@ -46,6 +46,7 @@
#include "XYList.h"
#include "EpsXmlInput.h"
#include "WrepJSon.h"
+#include "GeoJSon.h"
#include "SymbolPlotting.h"
#include "Contour.h"
#include "Wind.h"
@@ -65,7 +66,7 @@
#include "MetaData.h"
-#ifdef MAGICS_SPOT
+#ifdef HAVE_SPOT
#include "ClassicMtgDecoder.h"
#include "EpsgramDecoder.h"
#include "MetgramGraph.h"
@@ -76,15 +77,15 @@
using namespace magics;
XmlMagics::XmlMagics() : root_(0),
- gribloop_(0),
- geographical_(true),
+ gribloop_(0),
+ geographical_(true),
driversToSet_(true)
{
writeMagLog("magml");
actions_["magics"] = &XmlMagics::magics;
actions_["page"] = &XmlMagics::page;
-
+
actions_["mgb"] = &XmlMagics::binary;
actions_["text"] = &XmlMagics::text;
@@ -112,7 +113,7 @@ XmlMagics::XmlMagics() : root_(0),
actions_["wind"] = &XmlMagics::wind;
actions_["image"] = &XmlMagics::image;
- actions_["symbol"] = &XmlMagics::symbol;
+ actions_["symbol"] = &XmlMagics::symbol;
actions_["contour"] = &XmlMagics::contour;
actions_["histogram"] = &XmlMagics::histogram;
actions_["legend"] = &XmlMagics::legend;
@@ -133,8 +134,8 @@ XmlMagics::XmlMagics() : root_(0),
actions_["epsxml"] = &XmlMagics::epsxml;
actions_["wrepjson"] = &XmlMagics::wrepjson;
+ actions_["geojson"] = &XmlMagics::geojson;
-
actions_["epsbufr"] = &XmlMagics::epsbufr;
actions_["epsgraph"] = &XmlMagics::epsgraph;
actions_["epsgram"] = &XmlMagics::epsgram;
@@ -158,20 +159,20 @@ XmlMagics::XmlMagics() : root_(0),
}
-XmlMagics::~XmlMagics()
+XmlMagics::~XmlMagics()
{
}
-
+
/*!
Class information are given to the output-stream.
-*/
+*/
void XmlMagics::print(ostream& out) const
{
out << "XmlMagics[";
out << "]";
}
-void XmlMagics::execute(XmlTree& tree)
+void XmlMagics::execute(XmlTree& tree)
{
{
@@ -182,21 +183,21 @@ void XmlMagics::execute(XmlTree& tree)
MagLog::debug() << e.what() << endl;
}
- if ( driversToSet_ )
+ if ( driversToSet_ )
output_.set(drivers_);
- assert(root_);
+ ASSERT(root_);
root_->execute();
- if ( root_->scalingFactor() != 1)
+ if ( root_->scalingFactor() != 1)
drivers_.setOutputWidth(root_->scalingFactor());
drivers_.setDriversWidth(root_->absoluteWidth());
drivers_.setDriversHeight(root_->absoluteHeight());
- {
+ {
Timer timer("drivers", "rendering of the graphical tree");
drivers_.openDrivers();
drivers_.dispatch(root_->root());
@@ -206,13 +207,13 @@ void XmlMagics::execute(XmlTree& tree)
}
MetaDataVisitor::collect();
//root_->metadata(meta);
- /* later
+ /* later
std::map<string, string>::const_iterator filename = meta.find("filename");
if ( filename != meta.end() && !filename->second.empty()) {
ofstream file (filename->second.c_str());
-
+
for (std::map<string, string>::const_iterator d = meta.begin(); d != meta.end(); ++d) {
- if ( d != filename )
+ if ( d != filename )
file << d->first << " = " << d->second << "; " << endl;
}
}
@@ -225,12 +226,12 @@ void XmlMagics::execute(XmlTree& tree)
void XmlMagics::execute(const string& file, std::map<string, string>& )
{
-
+
XmlReader parser(true);
- XmlTree tree;
- ParameterManager::set(string("layout"), string("magml"));
+ XmlTree tree;
+ ParameterManager::set(string("layout"), string("magml"));
try {
- parser.interpret(file, &tree);
+ parser.interpret(file, &tree);
execute(tree);
}
catch (MagicsException& e) {
@@ -241,31 +242,31 @@ void XmlMagics::execute(const string& file, std::map<string, string>& )
void XmlMagics::display(const string& file)
{
XmlReader parser(true);
- XmlTree tree;
+ XmlTree tree;
try {
- parser.interpret(file, &tree);
+ parser.interpret(file, &tree);
tree.visit(*this);
}
catch (MagicsException& e) {
MagLog::debug() << e.what() << endl;
}
-
- if ( driversToSet_ )
+
+ if ( driversToSet_ )
output_.set(drivers_);
- assert(root_);
+ ASSERT(root_);
root_->getReady();
drivers_.setDriversWidth(root_->absoluteWidth());
drivers_.setDriversHeight(root_->absoluteHeight());
-
+
root_->execute();
drivers_.openDrivers();
drivers_.dispatch(root_->root());
drivers_.closeDrivers();
}
-
+
void XmlMagics::visit(const XmlNode& node)
{
std::map<string, Action>::iterator action = actions_.find(node.name());
@@ -280,7 +281,7 @@ void XmlMagics::visit(const XmlNode& node)
void XmlMagics::magics(const XmlNode& node)
{
- ParameterManager::set(string("layout"), string("magml"));
+ ParameterManager::set(string("layout"), string("magml"));
const float version_ = 3.0;
MagLog::debug() << " You are using the " << fixed << setprecision(1) << version_ << " version of the magml interpreter\n";
string version = node.getAttribute("version");
@@ -295,12 +296,12 @@ void XmlMagics::magics(const XmlNode& node)
sv >> v;
if ( v < version_ )
{
- MagLog::error() << " The version defined in the file is " << fixed << setprecision(1) << v
+ MagLog::error() << " The version defined in the file is " << fixed << setprecision(1) << v
<< "\n Compatibilty issue: check your magml file and update the version number" << endl;
return;
}
string method = node.getAttribute("method") ;
-
+
if ( method == "wrep" )
root_ = new WrepRootSceneNode();
else if ( method == "legacy" )
@@ -376,8 +377,8 @@ void XmlMagics::legend(const XmlNode& node)
{
LegendVisitor* legend = new XmlLegendVisitor();
legend->set(node);
-
- top()->legend(legend);
+
+ top()->legend(legend);
node.visit(*this);
}
@@ -386,7 +387,7 @@ void XmlMagics::text(const XmlNode& node)
XmlTextVisitor* text = new XmlTextVisitor();
text->set(node);
top()->text(text);
-
+
node.visit(*this);
}
@@ -406,21 +407,21 @@ void XmlMagics::map(const XmlNode& node)
}
void XmlMagics::binary(const XmlNode& node)
-{
+{
BinaryObject* binary = new BinaryObject();
binary->set(node);
top()->push_back(binary);
}
void XmlMagics::coastlines(const XmlNode& node)
-{
+{
Coastlines* coast = new Coastlines();
coast->set(node);
top()->push_back(coast);
}
void XmlMagics::taylor(const XmlNode& node)
-{
+{
TaylorGrid* grid = new TaylorGrid();
grid->set(node);
top()->push_back(grid);
@@ -432,26 +433,26 @@ void XmlMagics::tephigrid(const XmlNode& node)
top()->push_back(grid);
}
void XmlMagics::horizontalAxis(const XmlNode& node)
-{
+{
HorizontalAxis* axis = new HorizontalAxis();
axis->set(node);
top()->push_back(axis);
}
void XmlMagics::verticalAxis(const XmlNode& node)
-{
+{
VerticalAxis* axis = new VerticalAxis();
axis->set(node);
top()->push_back(axis);
}
void XmlMagics::cartesian(const XmlNode&)
-{
+{
geographical_ = false;
}
void XmlMagics::geographical(const XmlNode&)
-{
+{
geographical_ = true;
}
@@ -462,7 +463,7 @@ void XmlMagics::layer(const XmlNode& node)
VisualAction* action = new VisualAction();
action->set(node);
top()->push_back(action);
- push(action);
+ push(action);
}
else {
VisualAction* action = new VisualAction();
@@ -475,7 +476,7 @@ void XmlMagics::layer(const XmlNode& node)
pop();
}
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
GribDecoder* grib_handler;
void XmlMagics::gribloop(const XmlNode& node)
@@ -493,10 +494,10 @@ void XmlMagics::gribloop(const XmlNode& node)
}
-void XmlMagics::splitinloop(const XmlNode& )
+void XmlMagics::splitinloop(const XmlNode& )
{
/* later!
- assert(gribloop_);
+ ASSERT(gribloop_);
LayerNode* layer = new LayerNode();
layer->set(node);
@@ -509,8 +510,8 @@ void XmlMagics::splitinloop(const XmlNode& )
}
void XmlMagics::gribinloop(const XmlNode&)
-{
- assert(gribloop_);
+{
+ ASSERT(gribloop_);
top()->data(gribloop_->current());
}
@@ -529,7 +530,7 @@ void XmlMagics::gribloop(const XmlNode&)
}
void XmlMagics::gribinloop(const XmlNode&)
-{
+{
MagLog::warning() <<" Attempt to call GribInLoop but GRIB support is disabled!"<< endl;
}
@@ -542,7 +543,7 @@ void XmlMagics::grib(const XmlNode&)
#include "GeoPointsDecoder.h"
void XmlMagics::geopoints(const XmlNode& node)
-{
+{
GeoPointsDecoder* geo = new GeoPointsDecoder();
geo->set(node);
top()->data(geo);
@@ -550,7 +551,7 @@ void XmlMagics::geopoints(const XmlNode& node)
#include "MapGenDecoder.h"
void XmlMagics::mapgen(const XmlNode& node)
-{
+{
if (geographical_) {
MapGenDecoder* mapgen = new MapGenDecoder();
mapgen->set(node);
@@ -564,7 +565,7 @@ void XmlMagics::mapgen(const XmlNode& node)
}
void XmlMagics::xyinput(const XmlNode& node)
-{
+{
if (geographical_) {
XYList* list = new XYList();
list->set(node);
@@ -588,7 +589,7 @@ void XmlMagics::input(const XmlNode& node)
#include "GraphPlotting.h"
void XmlMagics::graph(const XmlNode& node)
-{
+{
GraphPlotting* graph = new GraphPlotting();
graph->set(node);
top()->visdef(graph);
@@ -610,17 +611,17 @@ void XmlMagics::histogram(const XmlNode& node)
***************************************************************************/
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
#include "OdaDecoder.h"
#endif
void XmlMagics::odb(const XmlNode& node)
{
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
OdaGeoDecoder* odb = new OdaGeoDecoder();
odb->set(node);
top()->data(odb);
-#else
+#else
MagLog::warning() << "ODB support is NOT enabled!\n";
#endif
@@ -630,8 +631,8 @@ void XmlMagics::odb(const XmlNode& node)
void XmlMagics::efigram(const XmlNode& node)
-{
-#ifdef MAGICS_SPOT
+{
+#ifdef HAVE_SPOT
EfigramDecoder* efi = new EfigramDecoder();
efi->set(node);
top()->data(efi);
@@ -639,14 +640,14 @@ void XmlMagics::efigram(const XmlNode& node)
}
void XmlMagics::cdfgraph(const XmlNode& node)
-{
+{
CdfGraph* cdf = new CdfGraph();
cdf->set(node);
top()->visdef(cdf);
}
void XmlMagics::efigraph(const XmlNode& node)
-{
+{
EfiGraph* efi = new EfiGraph();
efi->set(node);
top()->visdef(efi);
@@ -654,22 +655,22 @@ void XmlMagics::efigraph(const XmlNode& node)
void XmlMagics::epsplume(const XmlNode& node)
-{
+{
EpsPlume* plume = new EpsPlume();
plume->set(node);
top()->visdef(plume);
}
void XmlMagics::epsdirection(const XmlNode& node)
-{
+{
EpsDirection* direction = new EpsDirection();
direction->set(node);
top()->visdef(direction);
}
void XmlMagics::metgram(const XmlNode& node)
-{
-#ifdef MAGICS_SPOT
+{
+#ifdef HAVE_SPOT
ClassicMtgDecoder* metgram = new ClassicMtgDecoder();
metgram->set(node);
top()->data(metgram);
@@ -677,8 +678,8 @@ void XmlMagics::metgram(const XmlNode& node)
}
void XmlMagics::metgraph(const XmlNode& node)
-{
-#ifdef MAGICS_SPOT
+{
+#ifdef HAVE_SPOT
MetgramGraph* metgraph = new MetgramGraph();
metgraph->set(node);
top()->visdef(metgraph);
@@ -687,8 +688,8 @@ void XmlMagics::metgraph(const XmlNode& node)
void XmlMagics::epsgram(const XmlNode& node)
-{
-#ifdef MAGICS_SPOT
+{
+#ifdef HAVE_SPOT
EpsgramDecoder* eps = new EpsgramDecoder();
eps->set(node);
top()->data(eps);
@@ -696,26 +697,32 @@ void XmlMagics::epsgram(const XmlNode& node)
}
void XmlMagics::epsxml(const XmlNode& node)
-{
+{
EpsXmlInput* eps = new EpsXmlInput();
eps->set(node);
top()->data(eps);
}
void XmlMagics::wrepjson(const XmlNode& node)
-{
+{
WrepJSon* wrep = new WrepJSon();
wrep->set(node);
top()->data(wrep);
}
+void XmlMagics::geojson(const XmlNode& node)
+{
+ GeoJSon* geo = new GeoJSon();
+ geo->set(node);
+ top()->data(geo);
+}
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
#include "EpsBufr.h"
#endif
void XmlMagics::epsbufr(const XmlNode& node)
-{
-#ifdef MAGICS_BUFR
+{
+#ifdef HAVE_BUFR
EpsBufr* eps = new EpsBufr();
eps->set(node);
top()->data(eps);
@@ -723,28 +730,28 @@ void XmlMagics::epsbufr(const XmlNode& node)
}
void XmlMagics::epsgraph(const XmlNode& node)
-{
+{
EpsGraph* epsgraph = new EpsGraph();
epsgraph->set(node);
top()->visdef(epsgraph);
}
void XmlMagics::epswave(const XmlNode& node)
-{
+{
EpsWave* eps = new EpsWave();
eps->set(node);
top()->visdef(eps);
}
void XmlMagics::epswind(const XmlNode& node)
-{
+{
EpsWind* epswind = new EpsWind();
epswind->set(node);
top()->visdef(epswind);
}
void XmlMagics::epscloud(const XmlNode& node)
-{
+{
EpsCloud* epscloud = new EpsCloud();
epscloud->set(node);
top()->visdef(epscloud);
@@ -756,18 +763,18 @@ void XmlMagics::epsbar(const XmlNode& node)
top()->visdef(epsbar);
}
void XmlMagics::epsshading(const XmlNode& node)
-{
+{
EpsShade* eps = new EpsShade();
eps->set(node);
top()->visdef(eps);
}
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
#include "NetcdfDecoder.h"
#endif
void XmlMagics::netcdf(const XmlNode& node)
{
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
if ( geographical_ ) {
NetcdfDecoder* netcdf = new NetcdfDecoder();
netcdf->set(node);
@@ -790,7 +797,7 @@ void XmlMagics::table(const XmlNode& node)
#include "InputMatrix.h"
void XmlMagics::matrix(const XmlNode& node)
-{
+{
//MatrixTestDecoder* matrix = new MatrixTestDecoder();
//matrix->set(node);
if ( geographical_ ) {
@@ -821,7 +828,7 @@ void XmlMagics::polyline(const XmlNode& node)
void XmlMagics::symbol(const XmlNode& node)
-{
+{
if ( geographical_ ) {
SymbolPlotting* symbol = new SymbolPlotting();
symbol->set(node);
@@ -864,7 +871,7 @@ void XmlMagics::import(const XmlNode& node)
}
void XmlMagics::wind(const XmlNode& node)
-{
+{
if ( geographical_ ) {
Wind* wind = new Wind();
wind->set(node);
@@ -873,7 +880,7 @@ void XmlMagics::wind(const XmlNode& node)
else {
MagLog::warning() << " wind not yet implemented for cartesian system" << endl;
}
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
if ( gribloop_ ) gribloop_->next();
#endif
}
diff --git a/src/basic/XmlMagics.h b/src/basic/XmlMagics.h
index cb42f49..d4ac638 100644
--- a/src/basic/XmlMagics.h
+++ b/src/basic/XmlMagics.h
@@ -111,7 +111,7 @@ public:
void epsbufr(const XmlNode&);
void epsxml(const XmlNode&);
void wrepjson(const XmlNode&);
-
+ void geojson(const XmlNode&);
void epswind(const XmlNode&);
void epscloud(const XmlNode&);
void epsbar(const XmlNode&);
diff --git a/src/common/AnimationRules.cc b/src/common/AnimationRules.cc
index eeb864c..3747b5f 100644
--- a/src/common/AnimationRules.cc
+++ b/src/common/AnimationRules.cc
@@ -91,7 +91,7 @@ AsIsAnimationRules::~AsIsAnimationRules()
void AnimationRules::add(StepLayer& )
{
- assert(false);
+ ASSERT(false);
}
void AsIsAnimationRules::add(StepLayer& objects )
diff --git a/src/common/AutoLocker.cc b/src/common/AutoLocker.cc
index cd206e0..83f54f4 100644
--- a/src/common/AutoLocker.cc
+++ b/src/common/AutoLocker.cc
@@ -34,32 +34,10 @@ typedef map<void*,pthread_t,std::less<void*> > GotMap;
typedef map<pthread_t,void*,std::less<pthread_t> > WantMap;
static WantMap* wantMap = 0;
static GotMap* gotMap = 0;
-static Mutex* texmu = 0;
-typedef set<pthread_t,std::less<pthread_t> > Set;
-
-static pthread_once_t once = PTHREAD_ONCE_INIT;
-static void lock()
-{
-#ifdef CHECK_DEAD_LOCKS
- mutex->lock();
-#endif
-}
+typedef set<pthread_t,std::less<pthread_t> > Set;
-static void unlock()
-{
-#ifdef CHECK_DEAD_LOCKS
- mutex->unlock();
-#endif
-}
-static void init(void)
-{
- texmu = new Mutex;
- wantMap = new WantMap;
- gotMap = new GotMap;
- pthread_atfork(lock,unlock,unlock);
-}
void AutoLocker::want(void* resource)
diff --git a/src/common/BaseParameter.h b/src/common/BaseParameter.h
index d56931f..1a9885c 100644
--- a/src/common/BaseParameter.h
+++ b/src/common/BaseParameter.h
@@ -36,13 +36,13 @@
#include <PaperPoint.h>
#include "Matrix.h"
-#ifdef MAGICS_CAIRO
- #include "cairo.h"
+#ifdef HAVE_CAIRO
+ #include <cairo.h>
typedef cairo_t* CairoPtr;
#endif
#ifdef LATER
-#include "grib_api.h"
+#include <grib_api.h>
typedef grib_handle* GribHandlePtr ;
#endif
@@ -93,6 +93,10 @@ public:
virtual void setLocal(const magvector<int>&) { throw MistmatchType(name_, "integer", type()); }
virtual void get(magvector<int>&) const { throw MistmatchType(name_, "integer", type()); }
+ virtual void set(const magvector<long int>&) { throw MistmatchType(name_, "long integer", type()); }
+ virtual void setLocal(const magvector<long int>&) { throw MistmatchType(name_, "long integer", type()); }
+ virtual void get(magvector<long int>&) const { throw MistmatchType(name_, "long integer", type()); }
+
virtual void set(const string&) { throw MistmatchType(name_, "string", type()); }
virtual void setLocal(const string&) { throw MistmatchType(name_, "string", type()); }
virtual void get(string&) const { throw MistmatchType(name_, "string", type()); }
@@ -149,6 +153,10 @@ public:
virtual void setLocal(const magvector<int>&) { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "integer", type()) << "\n"; }
virtual void get(magvector<int>&) const { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "integer", type()) << "\n"; }
+ virtual void set(const magvector<long int>&) { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "long int", type()) << "\n"; }
+ virtual void setLocal(const magvector<long int>&) { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "long int", type()) << "\n"; }
+ virtual void get(magvector<long int>&) const { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "long int", type()) << "\n"; }
+
virtual void set(const string&) { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "string", type()) << "\n"; }
virtual void setLocal(const string&) { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "string", type()) << "\n"; }
virtual void get(string&) const { MagLog::dev()<< "Magics-warning:" << MistmatchType(name_, "string", type()) << "\n"; }
@@ -185,7 +193,7 @@ public:
virtual string type() const = 0;
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
virtual void set(const CairoPtr&) { throw MistmatchType(name_, "cairo_context", type()); }
virtual void get(CairoPtr&) const { throw MistmatchType(name_, "cairo_context", type()); }
string getType(CairoPtr) const { return "cairo_context"; }
@@ -202,6 +210,7 @@ public:
string getType(const double&) const { return "real"; }
string getType(const magvector<string>&) const { return "array of string"; }
string getType(const magvector<int>&) const { return "array of integer"; }
+ string getType(const magvector<long int>&) const { return "array of long integer"; }
string getType(const magvector<double>&) const { return "array of real"; }
string getType(LineStyle) const { return "LineStyle"; }
string getType(AxisAutomaticSetting) const { return "AxisAutomaticSetting"; }
@@ -209,6 +218,7 @@ public:
string getType(ArrowPosition) const { return "ArrowPosition"; }
string getType(Matrix) const { return "2DMatrix"; }
+
protected:
virtual void print(ostream&) const;
string name_;
diff --git a/src/common/BasePointsHandler.h b/src/common/BasePointsHandler.h
index 9c2cd9d..243f599 100644
--- a/src/common/BasePointsHandler.h
+++ b/src/common/BasePointsHandler.h
@@ -34,6 +34,7 @@
#include "UserPoint.h"
#include "VectorOfPointers.h"
+#include "MagException.h"
namespace magics {
@@ -95,13 +96,13 @@ public:
}
}
//! Method to set the current position to the first point.(abstract)
- virtual void setToFirst() {assert(false);};
+ virtual void setToFirst() {NOTIMP;};
//! Method to test the end of collection.
- virtual bool more() {assert(false);return false;};
+ virtual bool more() {NOTIMP;return false;};
//! Method to return the current value
- virtual const UserPoint& current() {assert(false);};
+ virtual const UserPoint& current() {NOTIMP;};
//! Method to advance
- virtual void advance() {assert(false);};
+ virtual void advance() {NOTIMP;};
virtual int size() {
points_ = 0;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 759dfed..a036f8f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -100,7 +100,7 @@ endforeach()
set( common_srcs ${common_srcs} PARENT_SCOPE )
set( common_templates ${common_templates} PARENT_SCOPE )
-if ( ENABLE_METVIEW )
+if ( HAVE_METVIEW )
list (APPEND metview_include
common/MagLog.h
common/MagTranslator.h
@@ -142,4 +142,4 @@ if ( ENABLE_METVIEW )
)
set( metview_include ${metview_include} PARENT_SCOPE )
endif()
-#install ( FILES ${CMAKE_CURRENT_SRC_DIR}/magics_api.h DESTINATION ${INSTALL_INCLUDE_DIR})
+install ( FILES magics_api.h DESTINATION ${INSTALL_INCLUDE_DIR})
diff --git a/src/common/Coordinate.h b/src/common/Coordinate.h
index 284d36e..ebd5226 100644
--- a/src/common/Coordinate.h
+++ b/src/common/Coordinate.h
@@ -95,7 +95,7 @@ public:
virtual double operator()(const string& val) const { return tonumber(val); }
virtual string type() const { return "regular"; }
- virtual void minmax(double max, double min) { assert(false); }
+ virtual void minmax(double max, double min) { NOTIMP; }
virtual void dataMinMax(double min, double max) = 0;
virtual void dataMinMax(double min, double max, const string&) = 0;
@@ -478,8 +478,8 @@ public:
def["x_automatic"]= "off";
}
- virtual void dataMinMax(double min, double max) { assert(false); }
- virtual void dataMinMax(double min, double max, const string&) { assert(false); }
+ virtual void dataMinMax(double min, double max) { NOTIMP; }
+ virtual void dataMinMax(double min, double max, const string&) { NOTIMP; }
AxisAutomaticSetting automatic() { return automatic_; }
virtual void automatic(bool automatic) { automatic_ = (automatic?m_both:m_off);}
virtual void setAutomatic(AxisAutomaticSetting automatic) { automatic_ = automatic; }
@@ -535,8 +535,8 @@ public:
double max() { return max_; }
double minpc() { return (*this)(min_); }
double maxpc() { return (*this)(max_); }
- virtual void dataMinMax(double min, double max) { assert(false); }
- virtual void dataMinMax(double min, double max, const string&) { assert(false); }
+ virtual void dataMinMax(double min, double max) { NOTIMP; }
+ virtual void dataMinMax(double min, double max, const string&) { NOTIMP; }
void minmax(double min, double max) {
switch ( automatic_ ) {
case m_both:
@@ -624,7 +624,7 @@ public:
string reference() { return DateTime(date_min_); }
virtual XCoordinate* clone() const {
XDateCoordinate* x = new XDateCoordinate();
- //x->copy(*this);
+
return x;
}
virtual string type() const { return "date"; }
diff --git a/src/common/Data.h b/src/common/Data.h
index ef095b1..9041c50 100644
--- a/src/common/Data.h
+++ b/src/common/Data.h
@@ -72,7 +72,7 @@ public:
class Data: public MetviewIcon{
public:
- Data(): name_("no_name"), binning_(0), dimension_(1), valid_(true) {}
+ Data(): name_("no_name"), binning_(0), dimension_(1), valid_(true), thinningFactor_(1) {}
virtual ~Data() { if ( binning_ ) delete binning_; }
//! Method to access the data as a matrix Used by pcont action routine
virtual MatrixHandler& matrix() { throw MethodNotYetImplemented("Data::matrix"); }
@@ -110,8 +110,8 @@ public:
virtual void customisedPoints(const AutomaticThinningMethod&, const Transformation& transformation, const std::set<string>& need , CustomisedPointsList& out)
{ customisedPoints(transformation, need, out, false); }
- virtual void customisedPoints(const BasicThinningMethod&, const Transformation& transformation, const std::set<string>& need , CustomisedPointsList& out)
- { customisedPoints(transformation, need, out, false); }
+ virtual void customisedPoints(const BasicThinningMethod& thinning, const Transformation& transformation, const std::set<string>& need , CustomisedPointsList& out)
+ { thinningFactor_ = thinning.factor(); customisedPoints(transformation, need, out, false); }
virtual void visit(TextVisitor&) {}
virtual void visit(LegendVisitor&) {}
virtual void visit(AnimationRules&) {}
@@ -158,6 +158,7 @@ protected:
int dimension_;
int index_;
bool valid_;
+ int thinningFactor_;
static int uniqueOwnerId_; // Metview usage for overlay control
DateDescription timeStamp_;
diff --git a/src/common/Factory.cc b/src/common/Factory.cc
index 939f24a..b6eeee4 100644
--- a/src/common/Factory.cc
+++ b/src/common/Factory.cc
@@ -77,7 +77,7 @@ B* SimpleFactory<B>::create(const string& name)
template<class B>
SimpleFactory<B>* SimpleFactory<B>::get(const string& name)
{
- assert(map_);
+ ASSERT(map_);
typename map<string, SimpleFactory<B>*>::iterator maker = (*map_).find(lowerCase(name));
if (maker != (*map_).end()) return (*maker).second;
#ifdef MAGICS_EXCEPTION
diff --git a/src/common/GeoRectangularProjection.cc b/src/common/GeoRectangularProjection.cc
index 547e381..973affa 100644
--- a/src/common/GeoRectangularProjection.cc
+++ b/src/common/GeoRectangularProjection.cc
@@ -121,7 +121,7 @@ void GeoRectangularProjection::revert(const vector< std::pair<double, double> >
}
return;
}
- assert(projection_);
+ ASSERT(projection_);
for ( vector< std::pair<double, double> >::const_iterator pt = input.begin(); pt != in_end; ++pt)
{
@@ -518,6 +518,10 @@ void MercatorProjection::init()
ypcmax_ = xy.y();
userEnveloppe_->clear();
PCEnveloppe_->clear();
+ askedxmin_ = std::min(xpcmin_, xpcmax_);
+ askedxmax_ = std::max(xpcmin_, xpcmax_);
+ askedymin_ = std::min(ypcmin_, ypcmax_);
+ askedymax_ = std::max(ypcmin_, ypcmax_);
}
void MercatorProjection::fast_reproject(double& x, double& y) const
diff --git a/src/common/Matrix.cc b/src/common/GribInterpretor.h
similarity index 99%
copy from src/common/Matrix.cc
copy to src/common/GribInterpretor.h
index 6ab743e..10c0783 100644
--- a/src/common/Matrix.cc
+++ b/src/common/GribInterpretor.h
@@ -177,9 +177,9 @@ void ProjectedMatrix::build()
void ProjectedMatrix::getReady()
{
- assert(!values_.empty());
- assert(!rowsArray_.empty());
- assert(!columnsArray_.empty());
+ ASSERT(!values_.empty());
+ ASSERT(!rowsArray_.empty());
+ ASSERT(!columnsArray_.empty());
// find the bounding box!
//columns_ = 100;
@@ -226,6 +226,7 @@ RotatedMatrix::RotatedMatrix(int rows, int columns): Matrix(rows, columns)
rowsArray_.reserve(rows*columns);
columnsArray_.reserve(rows*columns);
values_.reserve(rows*columns);
+
}
@@ -307,6 +308,8 @@ double Matrix::interpolate(double i, double j) const
return (*this)(ii, jj);
}
+
+
double Matrix::nearest(double row, double col,double &rowOut, double &colOut) const
{
double xleft = std::min( left(), right());
diff --git a/src/common/Layout.cc b/src/common/Layout.cc
index f8cec55..d69c8ec 100644
--- a/src/common/Layout.cc
+++ b/src/common/Layout.cc
@@ -49,7 +49,7 @@ Layout::Layout() :
owner_(0),animationRules_(0), transformation_(0),
width_(100), height_(100), x_(0), y_(0), display_(INLINE),
xmin_(0), xmax_(100), ymin_(0), ymax_(100),
- zoomable_(false), navigable_(false), resizable_(false), resolve_(false)
+ zoomable_(false), navigable_(false), resizable_(false), resolve_(false), clipping_(false)
{
}
@@ -221,13 +221,13 @@ double Layout::absoluteY() const
double Layout::absoluteWidth() const
{
- assert(parent_);
+ ASSERT(parent_);
return width_ * parent_->absoluteWidth() /100;
}
double Layout::absoluteHeight() const
{
- assert(parent_);
+ ASSERT(parent_);
return height_ * parent_->absoluteHeight() /100;
}
@@ -333,27 +333,28 @@ Layout* Layout::clone() const
{
Layout* layout = newLayout();
- layout->name_ = this->name_;
- layout->width_ = this->width_;
- layout->height_ = this->height_;
- layout->x_ = this->x_;
- layout->y_ = this->y_;
+ layout->name_ = name_;
+ layout->width_ = width_;
+ layout->height_ = height_;
+ layout->x_ = x_;
+ layout->y_ = y_;
- layout->xmin_ = this->xmin_;
- layout->xmax_ = this->xmax_;
- layout->ymin_ = this->ymin_;
- layout->ymax_ = this->ymax_;
- layout->transformation_ = this->transformation_;
- layout->parent_ = this->parent_;
+ layout->xmin_ = xmin_;
+ layout->xmax_ = xmax_;
+ layout->ymin_ = ymin_;
+ layout->ymax_ = ymax_;
+ layout->transformation_ = transformation_;
+ layout->parent_ = parent_;
- layout->id_ = this->id_;
- layout->zoomable_ = this->zoomable_;
- layout->navigable_ = this->navigable_;
- layout->zoomLevels_ = this->zoomLevels_;
- layout->zoomCurrentLevel_ = this->zoomCurrentLevel_;
- layout->widthResolution_ = this->widthResolution_;
- layout->heightResolution_ = this->heightResolution_;
- layout->resizable_ = this->resizable_;
+ layout->id_ = id_;
+ layout->zoomable_ = zoomable_;
+ layout->navigable_ = navigable_;
+ layout->zoomLevels_ = zoomLevels_;
+ layout->zoomCurrentLevel_ = zoomCurrentLevel_;
+ layout->widthResolution_ = widthResolution_;
+ layout->heightResolution_ = heightResolution_;
+ layout->resizable_ = resizable_;
+ layout->clipping_ = clipping_;
layout->frame(*this);
diff --git a/src/common/Layout.h b/src/common/Layout.h
index 58312b5..f138062 100644
--- a/src/common/Layout.h
+++ b/src/common/Layout.h
@@ -218,16 +218,18 @@ public:
AnimationRules* animationRules() const { return animationRules_; }
const Transformation& transformation() const {
- assert(transformation_);
+ ASSERT(transformation_);
return *transformation_;
}
- virtual bool childOfRoot() const { assert(parent_); return parent_->root(); }
+ virtual bool childOfRoot() const { ASSERT(parent_); return parent_->root(); }
void transformation(Transformation* );
void transformation(Layout& layout) const
{ layout.transformation(transformation_); }
void frameIt() { frame_.frame(*this); }
+ void clippIt(bool clipping) { clipping_ = clipping; }
+ bool clipp() const { return clipping_; }
void blankIt() { frame_.blank(*this); }
void resolve(bool resolve) { resolve_ = resolve; }
bool resolve() const { return resolve_; }
@@ -263,6 +265,8 @@ protected:
bool resizable_;
bool resolve_;
+ bool clipping_;
+
LayoutFrame frame_;
static vector<DriverInfo> driverInfos_;
diff --git a/src/common/MagException.h b/src/common/MagException.h
index 6aaaed5..ca10b16 100644
--- a/src/common/MagException.h
+++ b/src/common/MagException.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -31,18 +31,18 @@ class MagicsException : public exception
if (std::getenv("MAGICS_ABORT_EXCEPTION")) {
std::abort();
}
- }
+ }
MagicsException() : what_("") {
if (std::getenv("MAGICS_ABORT_EXCEPTION")) {
std::abort();
}
- }
+ }
virtual const char *what() const throw() { return what_.c_str(); }
virtual ~MagicsException() throw() {}
protected:
- virtual void print(ostream& out) const
+ virtual void print(ostream& out) const
{
out << what_;
}
@@ -59,35 +59,35 @@ class NoSuchFileException : public MagicsException
public:
NoSuchFileException( const string& file ):
MagicsException("No Such File: " + file){}
-};
+};
class NoWritePermissionException : public MagicsException
{
public:
NoWritePermissionException( const string& file ):
MagicsException("No write permission to write file: " + file){}
-};
-
+};
+
class NotYetImplemented : public MagicsException
{
public:
NotYetImplemented(const string& type, const string& method ):
MagicsException( type + " " + method + " : not yet implemented... "){}
-};
+};
class MethodNotYetImplemented : public NotYetImplemented
{
public:
MethodNotYetImplemented(const string& method):
- NotYetImplemented("Method", method) {}
-};
-
+ NotYetImplemented("Method", method) {}
+};
+
class ParameterNotYetImplemented : public NotYetImplemented
{
public:
ParameterNotYetImplemented(const string& param):
NotYetImplemented("Parameter", param){}
-};
+};
class AssertionFailed : public MagicsException {
public:
@@ -115,7 +115,11 @@ public:
#ifndef ASSERT
#define ASSERT(a) Assert(!(a),#a,__LINE__,__FILE__,__FUNCTION__)
-#endif
+#endif
+
+#ifndef NOTIMP
+#define NOTIMP throw MethodNotYetImplemented(__FUNCTION__)
+#endif
#endif
// EXCEPTION_H_
diff --git a/src/common/MagExceptions.h b/src/common/MagExceptions.h
index 27e14f0..a46a4dc 100644
--- a/src/common/MagExceptions.h
+++ b/src/common/MagExceptions.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -132,24 +132,24 @@ protected:
FileError() { }
};
-class CantOpenFile : public FileError {
+class CantOpenFile : public FileError {
bool retry_;
virtual bool retryOnServer() const { return retry_; }
public:
CantOpenFile(const string&,bool retry = false);
};
-class WriteError : public FileError {
+class WriteError : public FileError {
public:
WriteError(const string&);
};
-class ReadError : public FileError {
+class ReadError : public FileError {
public:
ReadError(const string&);
};
-class ShortFile : public ReadError {
+class ShortFile : public ReadError {
public:
ShortFile(const string&);
};
@@ -185,10 +185,10 @@ inline void Assert(int code,const char *msg,int line,const char *file,
*/
}
-inline void Panic(int code,const char *msg,int line,const char *file,
+inline void Panic(int code,const char *msg,int line,const char *file,
const char *proc)
{
- if(code != 0)
+ if(code != 0)
Panic(msg,line,file,proc);
}
@@ -207,7 +207,5 @@ public:
#define SYSCALL(a) SysCall(a,#a,__LINE__,__FILE__,__FUNCTION__)
#define ASSERT(a) Assert(!(a),#a,__LINE__,__FILE__,__FUNCTION__)
#define PANIC(a) Panic((a),#a,__LINE__,__FILE__,__FUNCTION__)
-#define NOTIMP throw NotImplemented(__LINE__,__FILE__,__FUNCTION__)
-
#endif
diff --git a/src/common/MagTranslator.h b/src/common/MagTranslator.h
index fb088e4..8570b7e 100644
--- a/src/common/MagTranslator.h
+++ b/src/common/MagTranslator.h
@@ -92,7 +92,7 @@ public:
}
};
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
template<>
class MagTranslator<cairo_t*, cairo_t*> {
public:
@@ -232,7 +232,28 @@ public:
}
};
+template<>
+class MagTranslator<string, longintarray> {
+public:
+ longintarray operator()(const string& value)
+ {
+ longintarray array;
+ vector<string> list;
+ Tokenizer tokenizer("/");
+ tokenizer(value, list);
+ for(vector<string>::const_iterator item = list.begin(); item != list.end(); ++item) {
+ array.push_back(atoi((*item).c_str()));
+ }
+ return array;
+ }
+ longintarray magics(const string& param)
+ {
+ longintarray from;
+ ParameterManager::get(param, from);
+ return from;
+ }
+};
template<>
class MagTranslator<intarray, intarray> {
public:
@@ -247,6 +268,20 @@ public:
return (*this)(from);
}
};
+template<>
+class MagTranslator<longintarray, longintarray> {
+public:
+ longintarray operator()(longintarray value)
+ {
+ return value;
+ }
+ longintarray magics(const string& param)
+ {
+ longintarray from;
+ ParameterManager::get(param, from);
+ return (*this)(from);
+ }
+};
template<>
class MagTranslator<const string&, const string&> {
diff --git a/src/common/MagicsCalls.cc b/src/common/MagicsCalls.cc
index debc7e9..6471517 100644
--- a/src/common/MagicsCalls.cc
+++ b/src/common/MagicsCalls.cc
@@ -171,7 +171,7 @@ public :
~GribFieldPosition() {}
bool operator()(int)
{
- assert(magics_);
+ ASSERT(magics_);
magics_->resetGrib();
return false;
}
@@ -433,6 +433,23 @@ public :
}
};
+/*! \brief nforms users that output_resolution is dreprecated
+
+ This parameter is not required anymore.
+*/
+class OutputResolution: public CompatibilityHelper {
+public :
+ OutputResolution() : CompatibilityHelper("output_resolution") {}
+ ~OutputResolution() {}
+ bool operator()(int )
+ {
+ MagLog::info() << "Deprecated parameter: output_resolution is not used anymore.\n"
+ << " Vector formats already used highes resolution and PNG uses 300 DPI."<< std::endl;
+ return true;
+ }
+};
+
+
class GraphValuesConverter : public CompatibilityHelper
{
public:
@@ -801,6 +818,7 @@ public :
}
};
+static OutputResolution outputresolution;
static WindArrowLegend windarrowlegend;
static PsFileName ps_file_name;
static GribSubareaExtraction grib_subarea_extraction;
@@ -820,6 +838,7 @@ static TextQuality axis_tick_label_quality("axis_tick_label");
static TextQuality axis_Title_quality("axis_title");
static TextQuality page_id_quality("page_id_line");
static TextQuality contour_label_quality("contour_label") ;
+static TextQuality map_label_quality("map_label_quality");
static WindArrowIndexHead wind_arrow_index_head;
static TextFontHeight text_reference_character_height("text_reference_character_height", "text_font_size");
@@ -852,7 +871,7 @@ static SimpleTranslator graph_shade_colour("graph_shade_colour", "graph_bar_colo
static SimpleTranslator graph_bar_colour("graph_bar_colour", "graph_shade_colour", true);
static SimpleTranslator subpage_map_area_definition("subpage_map_area_definition", "subpage_map_area_definition_polar", true);
static SimpleTranslator wind_arrow_legend("wind_arrow_legend", "legend");
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
static SimpleTranslator odb_latitude("odb_latitude", "odb_latitude_variable");
static SimpleTranslator odb_longitude("odb_longitude", "odb_longitude_variable");
static SimpleTranslator odb_y_component("odb_y_component", "odb_y_component_variable");
@@ -934,7 +953,7 @@ void ptest_()
void podb_()
{
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
magics_->podb();
#else
MagLog::warning() << "ODB support is NOT enabled!\n";
@@ -1177,6 +1196,10 @@ void pwrepjson_()
{
magics_->wrepjson();
}
+void pgeojson_()
+{
+ magics_->geojson();
+}
void pepsinput_()
{
magics_->epsinput();
@@ -1253,6 +1276,7 @@ void mag_symb() {psymb_();}
void mag_boxplot() {pboxplot_();}
void mag_taylor() {ptaylor_();}
void mag_tephi() {ptephi_();}
+void mag_geojson() { pgeojson_(); }
void mag_wrepjson() { pwrepjson_(); }
void mag_epsinput() { pepsinput_(); }
void mag_epscloud() { pepscloud_(); }
@@ -1310,7 +1334,7 @@ void mag_seti(const char* name, const int value)
void mag_setp(const char* name, void* value)
{
string n(name);
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
if ( magCompare(n, "output_cairo_drawing_context") ) {
ParameterManager::set("output_cairo_drawing_context", (CairoPtr)value);
}
diff --git a/src/common/MagicsSingleton.h b/src/common/MagicsSingleton.h
index 3f3b331..99c7a9c 100644
--- a/src/common/MagicsSingleton.h
+++ b/src/common/MagicsSingleton.h
@@ -80,20 +80,20 @@ public:
static void execute()
{
- assert(singleton_);
+ ASSERT(singleton_);
MagLog::dev() << "Execute --->" << *(singleton_->magics_->root()) << "\n";
singleton_->magics_->execute();
}
static VisualTask<UserPoint>* getGeoTask()
{
- assert(singleton_);
+ ASSERT(singleton_);
return singleton_->geoTask();
}
static VisualTask<UserPoint>* getXYTask()
{
- assert(singleton_);
+ ASSERT(singleton_);
return singleton_->xyTask();
}
diff --git a/src/common/Matrix.cc b/src/common/Matrix.cc
index 6ab743e..b8e7e3f 100644
--- a/src/common/Matrix.cc
+++ b/src/common/Matrix.cc
@@ -177,9 +177,9 @@ void ProjectedMatrix::build()
void ProjectedMatrix::getReady()
{
- assert(!values_.empty());
- assert(!rowsArray_.empty());
- assert(!columnsArray_.empty());
+ ASSERT(!values_.empty());
+ ASSERT(!rowsArray_.empty());
+ ASSERT(!columnsArray_.empty());
// find the bounding box!
//columns_ = 100;
@@ -307,6 +307,8 @@ double Matrix::interpolate(double i, double j) const
return (*this)(ii, jj);
}
+
+
double Matrix::nearest(double row, double col,double &rowOut, double &colOut) const
{
double xleft = std::min( left(), right());
diff --git a/src/common/Matrix.h b/src/common/Matrix.h
index 429f800..2268033 100644
--- a/src/common/Matrix.h
+++ b/src/common/Matrix.h
@@ -65,7 +65,7 @@ public :
virtual double height() const = 0;
virtual bool akimaEnable() const { return false; }
- virtual MatrixHandler* getReady(const Transformation&) const { assert(false); return 0;}
+ virtual MatrixHandler* getReady(const Transformation&) const { NOTIMP; return 0;}
diff --git a/src/common/MatrixHandler.h b/src/common/MatrixHandler.h
index 8322d4e..8454abe 100644
--- a/src/common/MatrixHandler.h
+++ b/src/common/MatrixHandler.h
@@ -332,10 +332,7 @@ public :
MatrixHandler* getReady(const Transformation& transformation) {
- if ( !&matrix_ )
- return 0;
return matrix_.getReady(transformation);
-
}
protected:
@@ -884,13 +881,13 @@ protected :
int columnIndex(int column) const
{
map<int, int>::const_iterator index = columnIndex_.find(column);
- assert( index != columnIndex_.end() );
+ ASSERT( index != columnIndex_.end() );
return index->second;
}
int rowIndex(int row) const
{
map<int, int>::const_iterator index = rowIndex_.find(row);
- assert( index != rowIndex_.end() );
+ ASSERT( index != rowIndex_.end() );
return index->second;
}
int frequencyRow_;
diff --git a/src/common/Node.cc b/src/common/Node.cc
index 05a4892..9e7402c 100644
--- a/src/common/Node.cc
+++ b/src/common/Node.cc
@@ -218,7 +218,7 @@ void RootNode::print(ostream& out) const
Layout& RootNode::getLayout()
{
- assert(frameNode_);
+ ASSERT(frameNode_);
return frameNode_->getLayout();
}
diff --git a/src/common/OutputFactory.cc b/src/common/OutputFactory.cc
index dc7a897..a52ea7b 100644
--- a/src/common/OutputFactory.cc
+++ b/src/common/OutputFactory.cc
@@ -26,6 +26,8 @@
#include "OutputFactory.h"
#include "DriverManager.h"
#include "PostScriptDriver.h"
+#include "KMLDriver.h"
+#include "GeoJsonDriver.h"
#ifdef MAGICS_RASTER
#include "GDDriver.h"
@@ -191,7 +193,7 @@ void QT_OutputFactory::set(DriverManager& magics, const XmlNode& node)
#endif
*/
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
#include "CairoDriver.h"
void CAIRO_PdfOutputFactory::set(DriverManager& magics, const XmlNode& node)
{
@@ -247,6 +249,7 @@ void CAIRO_SvgOutputFactory::set(DriverManager& magics, const XmlNode& node)
magics.push_back(driver);
}
+/*
void CAIRO_XOutputFactory::set(DriverManager& magics, const XmlNode& node)
{
CairoDriver* driver = new CairoDriver();
@@ -255,6 +258,7 @@ void CAIRO_XOutputFactory::set(DriverManager& magics, const XmlNode& node)
magics.push_back(driver);
}
+*/
void CAIRO_GeoTiffOutputFactory::set(DriverManager& magics, const XmlNode& node)
{
@@ -266,7 +270,6 @@ void CAIRO_GeoTiffOutputFactory::set(DriverManager& magics, const XmlNode& node)
}
#endif
-#include "KMLDriver.h"
void KML_KmlOutputFactory::set(DriverManager& magics, const XmlNode& node)
{
KMLDriver* driver = new KMLDriver();
@@ -274,3 +277,11 @@ void KML_KmlOutputFactory::set(DriverManager& magics, const XmlNode& node)
magics.push_back(driver);
}
+
+void GEOJSON_GeoJsonOutputFactory::set(DriverManager& magics, const XmlNode& node)
+{
+ GeoJsonDriver* driver = new GeoJsonDriver();
+ driver->set(node);
+
+ magics.push_back(driver);
+}
diff --git a/src/common/OutputFactory.h b/src/common/OutputFactory.h
index bf7cd1a..0656c27 100644
--- a/src/common/OutputFactory.h
+++ b/src/common/OutputFactory.h
@@ -202,7 +202,7 @@ public:
#endif
*/
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
class CAIRO_PngOutputFactory : public OutputFactory
{
public:
@@ -260,7 +260,7 @@ public:
virtual OutputFactory* clone() const { return new CAIRO_SvgOutputFactory(); }
virtual void set(DriverManager&, const XmlNode&);
};
-
+/*
class CAIRO_XOutputFactory : public OutputFactory
{
public:
@@ -270,6 +270,7 @@ public:
virtual OutputFactory* clone() const { return new CAIRO_XOutputFactory(); }
virtual void set(DriverManager&, const XmlNode&);
};
+*/
class CAIRO_GeoTiffOutputFactory : public OutputFactory
{
@@ -292,6 +293,16 @@ public:
virtual void set(DriverManager&, const XmlNode&);
};
+class GEOJSON_GeoJsonOutputFactory : public OutputFactory
+{
+public:
+ GEOJSON_GeoJsonOutputFactory() {}
+ virtual ~GEOJSON_GeoJsonOutputFactory() {}
+
+ virtual OutputFactory* clone() const {return new GEOJSON_GeoJsonOutputFactory();}
+ virtual void set(DriverManager&, const XmlNode&);
+};
+
template <>
class MagTranslator<string, OutputFactory> {
diff --git a/src/common/OutputHandler.cc b/src/common/OutputHandler.cc
index a8175c5..94968a7 100644
--- a/src/common/OutputHandler.cc
+++ b/src/common/OutputHandler.cc
@@ -61,6 +61,8 @@ void OutputHandler::set(const XmlNode& node, DriverManager& magics)
lineSpacing_ = 0.8;
else if (node.name() == "pdf" && factories_.empty() )
lineSpacing_ = 0.8;
+ else if (node.name() == "mgb" && factories_.empty() )
+ lineSpacing_ = 0.8;
else
lineSpacing_ = 1.2;
@@ -91,7 +93,7 @@ static SimpleObjectMaker<PS_EpsOutputFactory, OutputFactory> eps("eps");
static SimpleObjectMaker<PS_PdfOutputFactory, OutputFactory> ps_pdf("ps_pdf");
#ifdef MAGICS_RASTER
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
static SimpleObjectMaker<GD_PngOutputFactory, OutputFactory> gdpng("gd_png");
#else
static SimpleObjectMaker<GD_PngOutputFactory, OutputFactory> gdpng("png");
@@ -105,17 +107,18 @@ static SimpleObjectMaker<SVG_SvgOutputFactory, OutputFactory> svg("svg");
static SimpleObjectMaker<BinaryOutputFactory, OutputFactory> binary("mgb");
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
static SimpleObjectMaker<CAIRO_PngOutputFactory, OutputFactory> png("png");
static SimpleObjectMaker<CAIRO_PdfOutputFactory, OutputFactory> pdf("pdf");
-static SimpleObjectMaker<CAIRO_XOutputFactory, OutputFactory> x("x");
+//static SimpleObjectMaker<CAIRO_XOutputFactory, OutputFactory> x("x");
static SimpleObjectMaker<CAIRO_CairoOutputFactory, OutputFactory> cairo("cairo");
static SimpleObjectMaker<CAIRO_SvgOutputFactory, OutputFactory> csvg("cairo_svg");
static SimpleObjectMaker<CAIRO_PsOutputFactory, OutputFactory> cps("cairo_ps");
static SimpleObjectMaker<CAIRO_EpsOutputFactory, OutputFactory> ceps("cairo_eps");
-#ifdef MAGICS_GEOTIFF
+#ifdef HAVE_GEOTIFF
static SimpleObjectMaker<CAIRO_GeoTiffOutputFactory,OutputFactory> geotiff("geotiff");
#endif
#endif
static SimpleObjectMaker<KML_KmlOutputFactory, OutputFactory> kml("kml");
+static SimpleObjectMaker<GEOJSON_GeoJsonOutputFactory, OutputFactory> geojson("geojson");
diff --git a/src/common/ParameterManager.h b/src/common/ParameterManager.h
index a90763c..537a97f 100644
--- a/src/common/ParameterManager.h
+++ b/src/common/ParameterManager.h
@@ -18,12 +18,10 @@
/*! \file ParameterManager.h
\brief Handles the Magics Parameters
- \author Meteorological Visualisation Section, ECMWF
+ \author Development Section, ECMWF
Started: Jan 2004
- Changes:
-
*/
#ifndef ParameterManager_H
@@ -45,9 +43,8 @@ public :
UnknownParameter(const string& name) :
MagicsException(name + ": unknown parameter, the call is ignored.")
{
- MagLog::info() << "The parameter " << name << " is unknown in Magics++.\n"
- << "Please check the documentation or contact\n"
- << "the Meteorological Visualisation Section at ECMWF.\n";
+ MagLog::info() << "The parameter " << name << " is unknown in Magics.\n"
+ << "Please check the documentation or contact Software Support at ECMWF.\n";
}
};
@@ -63,7 +60,7 @@ public:
template <class T>
static void set(const string& name, const T& value)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (param)
{
@@ -81,7 +78,7 @@ public:
static void set(const string& name, const char* value)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (param)
try {
@@ -97,7 +94,7 @@ public:
static void setLocal(const BaseParameter* from)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(from->name());
if (param)
try {
@@ -113,7 +110,7 @@ public:
static void resetLocal(const string& name)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (param)
{
@@ -132,7 +129,7 @@ public:
static void reset(const string& name)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (param) param->reset();
}
@@ -144,7 +141,7 @@ public:
static BaseParameter* getCopy(const string& name)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
return (param) ? param->clone() : 0;
}
@@ -152,7 +149,7 @@ public:
template <class T>
static void get(const string& name, T& value)
{
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (param) param->get(value);
}
@@ -196,6 +193,12 @@ public:
return value;
}
+ static longintarray getLongIntArray(const string& name)
+ {
+ longintarray value;
+ get(name, value);
+ return value;
+ }
static bool getBool(const string& name)
{
@@ -219,7 +222,7 @@ public:
if (!table_) {
MagLog::error() << "Problem in setting the parameter [" << name << "] ---> contact Magics team" << endl;
}
- assert(table_);
+ ASSERT(table_);
BaseParameter* param = (*table_).parameter(name);
if (!param)
@@ -302,7 +305,7 @@ private:
// -- Friends
friend ostream& operator<<(ostream& s,const ParameterManager& p)
- { assert(table_); (*p.table_).print(s); return s; }
+ { ASSERT(table_); (*p.table_).print(s); return s; }
};
} // namespace magics
diff --git a/src/common/PolarStereographicProjection.cc b/src/common/PolarStereographicProjection.cc
index e6ee827..981a57d 100644
--- a/src/common/PolarStereographicProjection.cc
+++ b/src/common/PolarStereographicProjection.cc
@@ -120,7 +120,7 @@ double PolarStereographicProjection::height() const {
PaperPoint PolarStereographicProjection::operator()(const UserPoint& point) const
{
- assert(projection_);
+ ASSERT(projection_);
TeCoord2D geo = TeCoord2D(point.x()*TeCDR, point.y()*TeCDR);
TeCoord2D xy = projection_->LL2PC(geo);
@@ -137,7 +137,7 @@ PaperPoint PolarStereographicProjection::operator()(const PaperPoint& point) co
void PolarStereographicProjection::revert(const vector< std::pair<double, double> > & in, vector< std::pair<double, double> > & out) const
{
- assert(projection_);
+ ASSERT(projection_);
out.reserve(in.size());
for ( vector< std::pair<double, double> >::const_iterator pt = in.begin(); pt != in.end(); ++pt) {
@@ -153,7 +153,7 @@ void PolarStereographicProjection::revert(const vector< std::pair<double, double
void PolarStereographicProjection::revert(const PaperPoint& xy, UserPoint& point) const
{
- assert(projection_);
+ ASSERT(projection_);
TeCoord2D texy = TeCoord2D(xy.x(), xy.y());
TeCoord2D geo = projection_->PC2LL(texy);
@@ -616,7 +616,7 @@ void PolarStereographicProjection::labels(const LabelPlotting& label, DrawingVis
label.add(text); // This will set the font!
text->setText(writeLatitude(point));
text->push_back(xy);
- text->setBlanking(true);
+
}
}
@@ -770,7 +770,7 @@ void PolarStereographicProjection::thin(MatrixHandler& matrix, double x, double
}
else {
double coeff = (1-((lat/90.)*(lat/90.)));
- assert ( coeff != 0);
+ ASSERT ( coeff != 0);
incrementx = yfactor / coeff;
if (incrementx < 0 )
incrementx = 1;
diff --git a/src/common/PolarStereographicProjection.h b/src/common/PolarStereographicProjection.h
index 4ba9f32..595bddf 100644
--- a/src/common/PolarStereographicProjection.h
+++ b/src/common/PolarStereographicProjection.h
@@ -180,6 +180,7 @@ public:
void getNewDefinition(const UserPoint&, const UserPoint&, string&) const;
void setDefinition(const string&);
UserPoint reference() const;
+ virtual void geoProjection(int& geo) const { geo = 1; } // Useful for Streamlines !
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream&) const;
diff --git a/src/common/Proj4Projection.cc b/src/common/Proj4Projection.cc
index 5f8cae6..bd9504b 100644
--- a/src/common/Proj4Projection.cc
+++ b/src/common/Proj4Projection.cc
@@ -154,7 +154,7 @@ void EpsgConfig::init()
}
void Epsg::set(const json_spirit::Value& value)
{
- assert (value.type() == json_spirit::obj_type);
+ ASSERT (value.type() == json_spirit::obj_type);
json_spirit::Object object =value.get_value< json_spirit::Object >();
for (vector<json_spirit::Pair>::const_iterator entry = object.begin(); entry != object.end(); ++entry) {
@@ -170,7 +170,7 @@ void EpsgConfig::callback(const string& name, const json_spirit::Value& value)
// here we get an Array of epsg!
- assert (value.type() == json_spirit::array_type);
+ ASSERT (value.type() == json_spirit::array_type);
json_spirit::Array values = value.get_value<json_spirit::Array>();
for (unsigned int i = 0; i < values.size(); i++) {
json_spirit::Object object = values[i].get_value< json_spirit::Object >();
@@ -254,7 +254,7 @@ void Proj4Projection::init()
if ( !to_) {
MagLog::error() << pj_strerrno(pj_errno) << endl;
MagLog::error() << " proj4 error " << projection_->definition() << endl;
- assert(false);
+ ASSERT(false);
}
@@ -284,7 +284,10 @@ void Proj4Projection::init()
full();
}
-
+ askedxmin_ = std::min(min_pcx_, max_pcx_);
+ askedxmax_ = std::max(min_pcx_, max_pcx_);
+ askedymin_ = std::min(min_pcy_, max_pcy_);
+ askedymax_ = std::max(min_pcy_, max_pcy_);
}
void Proj4Projection::full()
diff --git a/src/common/Proj4Projection.h b/src/common/Proj4Projection.h
index 50f6912..b48c849 100644
--- a/src/common/Proj4Projection.h
+++ b/src/common/Proj4Projection.h
@@ -215,6 +215,7 @@ public:
void getNewDefinition(const UserPoint&, const UserPoint&, string&) const;
void setDefinition(const string&);
void reprojectComponents(double&, double&, pair<double, double>&) const;
+ virtual void geoProjection(int& geo) const { geo = 1; } // Useful for Streamlines !
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
typedef void (Proj4Projection::*SettingHelper)();
diff --git a/src/common/TableDefinition.h b/src/common/TableDefinition.h
index b11189e..03044ef 100644
--- a/src/common/TableDefinition.h
+++ b/src/common/TableDefinition.h
@@ -79,13 +79,13 @@ class TableDefinitionInterface
public:
TableDefinitionInterface() : helper_(0) {}
virtual void set(const XmlNode& node)
- { assert(helper_); helper_->set(node); }
- int size() { assert(helper_); return helper_->size(); }
- typename TableDefinition<T>::TableIterator begin() { assert(helper_); return helper_->begin(); }
- typename TableDefinition<T>::TableIterator end() { assert(helper_); return helper_->end(); }
- void adjust(T min, T max) { assert(helper_); helper_->adjust(min, max); }
- bool empty() { assert(helper_); return helper_->empty(); }
- void push_back(T val) { assert(helper_); helper_->push_back(val); }
+ { ASSERT(helper_); helper_->set(node); }
+ int size() { ASSERT(helper_); return helper_->size(); }
+ typename TableDefinition<T>::TableIterator begin() { ASSERT(helper_); return helper_->begin(); }
+ typename TableDefinition<T>::TableIterator end() { ASSERT(helper_); return helper_->end(); }
+ void adjust(T min, T max) { ASSERT(helper_); helper_->adjust(min, max); }
+ bool empty() { ASSERT(helper_); return helper_->empty(); }
+ void push_back(T val) { ASSERT(helper_); helper_->push_back(val); }
protected:
diff --git a/src/common/TaylorProjection.cc b/src/common/TaylorProjection.cc
index 1b709ba..1dbf4a9 100644
--- a/src/common/TaylorProjection.cc
+++ b/src/common/TaylorProjection.cc
@@ -216,7 +216,7 @@ Polyline& TaylorProjection::getUserBoundingBox() const
void TaylorProjection::setDefinition(const string& def)
{
- assert(def.empty());
+ ASSERT(def.empty());
}
diff --git a/src/common/ThreadControler.cc b/src/common/ThreadControler.cc
index 3c6ca0b..3f6fc31 100644
--- a/src/common/ThreadControler.cc
+++ b/src/common/ThreadControler.cc
@@ -153,7 +153,7 @@ void *ThreadControler::startThread(void *data)
void ThreadControler::start()
{
- assert(thread_ == 0);
+ ASSERT(thread_ == 0);
pthread_attr_t attr;
pthread_attr_init(&attr);
diff --git a/src/common/Transformation.h b/src/common/Transformation.h
index c2fff51..5f470e0 100644
--- a/src/common/Transformation.h
+++ b/src/common/Transformation.h
@@ -114,7 +114,10 @@ public:
virtual void cleanPCEnveloppe();
void cleaninit();
enum CoordinateType {GeoType,XyType};
- CoordinateType coordinateType() const {return coordinateType_;}
+ CoordinateType coordinateType() const {return coordinateType_;}
+
+ virtual void geoProjection(int& geo) const { geo = 0; } // Useful for Streamlines !
+
virtual void toxml(ostream&) const {}
// Xml Methods !
virtual void set(const map<string, string>& ) {}
@@ -126,8 +129,8 @@ public:
return object;
}
- virtual Polyline& getUserBoundingBox() const { assert(false);}
- virtual Polyline& getPCBoundingBox() const { assert(false);}
+ virtual Polyline& getUserBoundingBox() const { NOTIMP;}
+ virtual Polyline& getPCBoundingBox() const { NOTIMP;}
bool needTopAxis() const { return topAxis_; }
void needTopAxis(bool top) { topAxis_ = top; }
@@ -138,7 +141,7 @@ public:
string writeLatitude(const UserPoint&) const;
virtual bool wrapAround(const Polyline&) const { return false; }
- virtual void coastSetting(map<string, string>&, double, double) const { assert(false); }
+ virtual void coastSetting(map<string, string>&, double, double) const { NOTIMP; }
virtual bool verifyDef(const string&) const { return false; }
@@ -198,7 +201,7 @@ public:
virtual void fast_reproject(double& x, double& y) const
{ }
- virtual double patchDistance(double) const { assert(false); return 0;}
+ virtual double patchDistance(double) const { NOTIMP; }
virtual PaperPoint operator()(const PaperPoint& xy) const
{ return xy; }
@@ -296,9 +299,9 @@ public:
virtual void thin(double, PaperPoint&, vector<pair<double, double> >&) const;
virtual void thin(double, PaperPoint&, Matrix&, double) const;
virtual void getNewDefinition(const UserPoint&, const UserPoint&, string&) const
- { assert(false); }
+ { NOTIMP; }
virtual void setDefinition(const string&)
- { assert(false); }
+ { NOTIMP; }
virtual void thin(MatrixHandler&, double x, double y, vector<UserPoint>&) const;
diff --git a/src/common/UserPoint.h b/src/common/UserPoint.h
index a16dd82..780e1e8 100644
--- a/src/common/UserPoint.h
+++ b/src/common/UserPoint.h
@@ -71,27 +71,7 @@ public:
double x_;
double y_;
double value_;
- /*
- bool in(double left, double right, double bottom, double top,std::stack<UserPoint*>& points)
- {
- double miny = std::min(top, bottom);
- double maxy = std::max(top, bottom);
- double minx = std::min(left, right);
- double maxx = std::max(left, right);
-
- if (y_ > maxy)
- return false;
- if (y_ < miny)
- return false;
- if (x_ < minx)
- return false;
- if (x_ > maxx)
- return false;
- UserPoint* point = this;
- points.push(point);
- return true;
- }
- */
+
void high(bool high) { high_ = high; }
void low(bool low) { low_ = low; }
bool high() const { return high_; }
@@ -110,7 +90,7 @@ public:
string asLongitude() const
{
ostringstream lon;
-// string ew = "#232"; // degree symbol
+
string ew = "°";
UserPoint nice = shift(-180, 180);
@@ -124,7 +104,7 @@ public:
string asLatitude() const
{
ostringstream lat;
- //string ns = "#232"; // degree symbol
+
string ns = "°";
if ( y_ < 0 ) ns += "S";
if ( y_ >= 0 ) ns += "N";
diff --git a/src/common/magics_api.h b/src/common/magics_api.h
index af912f1..f9a4487 100644
--- a/src/common/magics_api.h
+++ b/src/common/magics_api.h
@@ -56,7 +56,7 @@ void mag_taylor();
void mag_tephi();
void mag_input();
void mag_table();
-
+void mag_geojson();
void mag_wrepjson();
void mag_epsinput();
void mag_epscloud();
diff --git a/src/decoders/BinningObject.cc b/src/decoders/BinningObject.cc
index a00028f..418f239 100644
--- a/src/decoders/BinningObject.cc
+++ b/src/decoders/BinningObject.cc
@@ -203,7 +203,7 @@ Matrix* BinningObject::operator()(PointsList& points)
}
double columns = matrix->columns();
- double rows = matrix->rows();
+
points.setToFirst();
while ( points.more() ) {
const UserPoint& point = points.current();
diff --git a/src/decoders/BoxPlotDecoder.h b/src/decoders/BoxPlotDecoder.h
index 53c5a9d..ac9063a 100644
--- a/src/decoders/BoxPlotDecoder.h
+++ b/src/decoders/BoxPlotDecoder.h
@@ -59,7 +59,7 @@ public:
{
customisedPoints(n, out);
}
- PointsHandler& points(const Transformation&, bool) { assert(false); }
+ PointsHandler& points(const Transformation&, bool) { NOTIMP; }
void getReady(const Transformation&);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
diff --git a/src/decoders/CMakeLists.txt b/src/decoders/CMakeLists.txt
index cfbb785..a65859b 100644
--- a/src/decoders/CMakeLists.txt
+++ b/src/decoders/CMakeLists.txt
@@ -59,7 +59,7 @@ foreach( file ${_decoders_srcs} )
list( APPEND decoders_srcs decoders/${file} )
endforeach()
-if (MAGICS_GRIB)
+if (HAVE_GRIB)
list( APPEND decoders_srcs
decoders/GribAddressMode.h
decoders/GribDecoder.cc
@@ -75,7 +75,7 @@ decoders/GribSatelliteInterpretor.h
endif()
-if (MAGICS_NETCDF)
+if (HAVE_NETCDF)
list( APPEND decoders_srcs
#Netcdf--->
decoders/NetcdfOrcaInterpretor.cc
@@ -102,7 +102,7 @@ decoders/NetcdfVectorInterpretor.h
)
endif()
-if (MAGICS_BUFR)
+if (HAVE_BUFR)
list( APPEND decoders_srcs
# Bufr --->
decoders/EpsBufr.cc
@@ -115,7 +115,7 @@ decoders/ObsDecoder.h
endif()
-if (MAGICS_SPOT)
+if (HAVE_SPOT)
list( APPEND decoders_srcs
#Spot --->
decoders/ClassicMtgDecoder.cc
@@ -128,7 +128,7 @@ endif()
set( decoders_srcs ${decoders_srcs} PARENT_SCOPE )
-if ( ENABLE_METVIEW )
+if ( HAVE_METVIEW )
list (APPEND metview_include
decoders/DateTime.h
decoders/GribDecoder.h
diff --git a/src/decoders/ClassicMtgDecoder.cc b/src/decoders/ClassicMtgDecoder.cc
index c4fb42d..3154c0f 100644
--- a/src/decoders/ClassicMtgDecoder.cc
+++ b/src/decoders/ClassicMtgDecoder.cc
@@ -662,7 +662,7 @@ void ClassicMtgDecoder::visit(Transformation& transformation)
{
decode();
- assert(parameter_);
+ ASSERT(parameter_);
parameter_->setTransformation(transformation);
diff --git a/src/decoders/ClassicMtgDecoder.h b/src/decoders/ClassicMtgDecoder.h
index 6aa322f..94dfe0f 100644
--- a/src/decoders/ClassicMtgDecoder.h
+++ b/src/decoders/ClassicMtgDecoder.h
@@ -124,7 +124,7 @@ public:
void customisedPoints(const std::set<string>&, CustomisedPointsList&);
void customisedPoints(const Transformation&, const std::set<string>& n, CustomisedPointsList& out, bool)
{ customisedPoints(n, out); }
- PointsHandler& points(const Transformation&, bool) { assert(false); }
+ PointsHandler& points(const Transformation&, bool) { NOTIMP; }
void visit(TextVisitor&);
void moreTitle(TextVisitor&);
void visit(Transformation&);
diff --git a/src/decoders/EpsXmlInput.h b/src/decoders/EpsXmlInput.h
index 0884c4f..0bfb1fc 100644
--- a/src/decoders/EpsXmlInput.h
+++ b/src/decoders/EpsXmlInput.h
@@ -68,7 +68,7 @@ public:
{
customisedPoints(n, out);
}
- PointsHandler& points(const Transformation& t, bool) { assert(false);}
+ PointsHandler& points(const Transformation& t, bool) { NOTIMP;}
virtual void visit(TextVisitor&);
virtual void visit(MetaDataVisitor&);
diff --git a/src/decoders/EpsgramDecoder.cc b/src/decoders/EpsgramDecoder.cc
index 35d82bf..6be5ed1 100644
--- a/src/decoders/EpsgramDecoder.cc
+++ b/src/decoders/EpsgramDecoder.cc
@@ -1920,7 +1920,7 @@ void SpotDecoder::visit(Transformation& transformation)
{
return;
}
- assert(parameter_);
+ ASSERT(parameter_);
parameter_->setTransformation(transformation);
}
diff --git a/src/decoders/EpsgramDecoder.h b/src/decoders/EpsgramDecoder.h
index f74b06c..733802d 100644
--- a/src/decoders/EpsgramDecoder.h
+++ b/src/decoders/EpsgramDecoder.h
@@ -89,7 +89,7 @@ public:
void shift(double shift) { shift_ = shift; }
virtual void stepvalues(double step, vector<double>& xpos) { xpos.push_back( step); }
virtual void xvalues(double, vector<double>&) {}
- virtual double plumesInterval() { assert(false); }
+ virtual double plumesInterval() { NOTIMP; }
void type(const string& type) { type_ = type; }
protected:
diff --git a/src/decoders/GeoPointsDecoder.cc b/src/decoders/GeoPointsDecoder.cc
index c9d8838..485cfaf 100644
--- a/src/decoders/GeoPointsDecoder.cc
+++ b/src/decoders/GeoPointsDecoder.cc
@@ -73,6 +73,7 @@ void GeoPointsDecoder::add(const Transformation& transformation, CustomisedPoint
UserPoint p = duplicates.top();
push_back(new UserPoint(p));
CustomisedPoint* cp = new CustomisedPoint(p.x(), p.y(), point.identifier());
+
for ( CustomisedPoint::iterator key = point.begin(); key != point.end(); ++key)
cp->insert(make_pair(key->first, key->second));
customisedPoints_.push_back(cp);
@@ -96,7 +97,7 @@ void GeoPointsDecoder::yxdtlv2(const string& line, const Transformation& transfo
std::istringstream in(line);
double lat, lon, date, time, level, value;
in >> lat >> lon >> level >> date >> time >> value;
- UserPoint geo(lon, lat, value);
+ UserPoint geo(lon, lat, value, value == missing_);
add(transformation, geo);
}
@@ -105,7 +106,7 @@ void GeoPointsDecoder::xyv2(const string& line, const Transformation& transforma
std::istringstream in(line);
double lat, lon, value;
in >> lon >> lat >> value;
- UserPoint geo(lon, lat, value);
+ UserPoint geo(lon, lat, value, value == missing_);
add(transformation, geo);
}
@@ -117,6 +118,8 @@ void GeoPointsDecoder::lluv(const string& line, const Transformation& transforma
CustomisedPoint geo(lon, lat, "lluv");
geo["x_component"] = u;
geo["y_component"] = v;
+ if ( u == missing_ || v == missing_ )
+ geo.missing(true);
add(transformation, geo);
}
@@ -125,12 +128,20 @@ void GeoPointsDecoder::polar(const string& line, const Transformation& transform
std::istringstream in(line);
double lat, lon, height, date, time, speed, direction;
in >> lat >> lon >> height >> date >> time >> speed >> direction;
+
CustomisedPoint geo(lon, lat, "polar");
- double angle = (90 - (direction))*(PI/180.);
+
+ if ( speed == missing_ || direction == missing_ )
+ geo.missing(true);
+
+ else {
+ double angle = (90 - (direction))*(PI/180.);
+ geo["x_component"] = speed * -cos(angle);
+ geo["y_component"] = speed * -sin(angle) ;
+ }
+
- geo["x_component"] = speed * -cos(angle);
- geo["y_component"] = speed * -sin(angle) ;
add(transformation, geo);
}
@@ -140,7 +151,7 @@ void GeoPointsDecoder::yxdtlv1(const string& line)
double lat, lon, date, time, level, value;
in >> lat >> lon >> level >> date >> time >> value;
- push_back(new UserPoint(lon, lat, value));
+ push_back(new UserPoint(lon, lat, value, value == missing_));
}
void GeoPointsDecoder::xyv1(const string& line)
@@ -148,7 +159,7 @@ void GeoPointsDecoder::xyv1(const string& line)
std::istringstream in(line);
double lat, lon, value;
in >> lon >> lat >> value;
- push_back(new UserPoint(lon, lat, value));
+ push_back(new UserPoint(lon, lat, value, value == missing_));
}
void GeoPointsDecoder::decode(const Transformation& transformation)
@@ -261,9 +272,7 @@ void GeoPointsDecoder::initInfo()
setInfo("_datatype","GEOPOINTS");
setInfo("path",path_);
setInfo("MV_Format","GEOPOINTS");
- //setInfo("value",getValue());
- //setInfo("x",getX());
- //setInfo("y",getY());
+
}
void GeoPointsDecoder::visit(MetaDataCollector& mdc)
@@ -288,9 +297,7 @@ void GeoPointsDecoder::visit(ValuesCollector& points)
if(points.size() <=0 || size() == 0)
return;
- //if(value_.empty())
- // points.setHasValue(false);
-
+
for (ValuesCollector::iterator point = points.begin(); point != points.end(); ++point)
{
double lat=(*point).y();
diff --git a/src/decoders/GribAddressMode.h b/src/decoders/GribAddressMode.h
index 6eab49a..309ad90 100644
--- a/src/decoders/GribAddressMode.h
+++ b/src/decoders/GribAddressMode.h
@@ -66,6 +66,10 @@ public:
MagLog::dev() << "GribAddressMode::toxml(ostream&, int = 0)---> to be checked!...\n";
return 0;
}
+ virtual grib_handle* operator()(grib_context*, FILE*, long int) const {
+ MagLog::dev() << "GribAddressMode::toxml(ostream&, int = 0)---> to be checked!...\n";
+ return 0;
+ }
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
@@ -98,10 +102,8 @@ public :
virtual grib_handle* operator()(grib_context*, FILE* file, int position) const
{
grib_handle* handle = 0;
- void* msg=NULL;
- size_t size=0;
- off_t offset=0;
- int err;
+
+
grib_context* context = grib_context_get_default();
int error;
for (int i = 0; i < position-1; i++)
@@ -134,14 +136,30 @@ public:
virtual grib_handle* operator()(grib_context* context, FILE* file, int position) const
{
- fseek(file, position, SEEK_SET);
+ long int offset = (long int) position;
+ cout << "OFFSET-->" << offset << endl;
+ fseek(file, (long int) position, SEEK_SET);
grib_handle* handle = 0;
int error;
handle = grib_handle_new_from_file(0, file, &error) ;
- return handle;
+
+ return handle;
}
+ virtual grib_handle* operator()(grib_context* context, FILE* file, long int position) const
+ {
+
+
+ fseek(file, position, SEEK_SET);
+ grib_handle* handle = 0;
+
+ int error;
+ handle = grib_handle_new_from_file(0, file, &error) ;
+
+ return handle;
+
+ }
protected :
void print(ostream& out) const { out << "GribAddressRecordMode\n"; }
diff --git a/src/decoders/GribDecoder.cc b/src/decoders/GribDecoder.cc
index f31e2ac..a1c50d4 100644
--- a/src/decoders/GribDecoder.cc
+++ b/src/decoders/GribDecoder.cc
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -42,254 +42,295 @@
#include "VisualAction.h"
#include "AnimationRules.h"
#include "Transformation.h"
+#include "MetaData.h"
+#include "MagJSon.h"
using namespace magics;
int GribDecoder::count_ = 0;
GribDecoder::GribDecoder() : matrix_(0), xComponent_(0), yComponent_(0),
- colourComponent_(0), handle_(0), interpretor_(0),
- field_(0), component1_(0), component2_(0), colour_(0)
+ colourComponent_(0), handle_(0), nearest_(0), interpretor_(0),
+ field_(0), component1_(0), component2_(0), colour_(0), xValues_(0), yValues_(0)
{
- count_++;
- title_ = "grib_" + tostring(count_);
- version();
+ count_++;
+ title_ = "grib_" + tostring(count_);
+ version();
}
void GribDecoder::version()
{
- static bool done = false;
- if ( done ) return;
- done = true;
- MagLog::info() << "GribAPI Version :" << grib_get_api_version() << endl;
+ static bool done = false;
+ if ( done ) return;
+ done = true;
+ MagLog::info() << "GribAPI Version :" << grib_get_api_version() << endl;
}
-GribDecoder::~GribDecoder()
+GribDecoder::~GribDecoder()
{
- if ( matrix_) delete matrix_;
- if ( xComponent_ ) delete xComponent_;
- if ( yComponent_ ) delete yComponent_;
- if ( handle_ ) {
+ if ( matrix_) delete matrix_;
+ if ( xComponent_ ) delete xComponent_;
+ if ( yComponent_ ) delete yComponent_;
+ if ( handle_ ) {
- grib_handle_delete (handle_);
+ grib_handle_delete (handle_);
- }
- for (PointsList::iterator point = points_.begin(); point != points_.end(); ++point) {
- delete *point;
- *point = 0;
- }
- if ( interpretor_ ) delete interpretor_;
+ }
+
+ if (nearest_)
+ grib_nearest_delete(nearest_);
- //context is a reference to a global context and should not be deleted
+ for (PointsList::iterator point = points_.begin(); point != points_.end(); ++point) {
+ delete *point;
+ *point = 0;
+ }
+ if ( interpretor_ ) delete interpretor_;
+
+ //context is a reference to a global context and should not be deleted
}
void GribDecoder::set(const GribLoop& loop, int index)
{
- // Copy the information about scaling...
- scaling_ = loop.scaling_;
- derived_scaling_ = loop.derived_scaling_;
- scaling_offset_ = loop.scaling_offset_;
- scaling_factor_ = loop.scaling_factor_;
- index_ = loop.uniqueId_;
- interpolation_method_ = loop.interpolation_method_;
- wind_mode_ = auto_ptr<WindMode>(loop.wind_mode_->clone());
- internalIndex_ = index;
+ // Copy the information about scaling...
+ scaling_ = loop.scaling_;
+ derived_scaling_ = loop.derived_scaling_;
+ scaling_offset_ = loop.scaling_offset_;
+ scaling_factor_ = loop.scaling_factor_;
+ index_ = loop.uniqueId_;
+ interpolation_method_ = loop.interpolation_method_;
+ missing_fill_count_ = loop.missing_fill_count_;
+ wind_mode_ = auto_ptr<WindMode>(loop.wind_mode_->clone());
+ internalIndex_ = index;
}
long computeStep( const GribDecoder& grib,const string& key)
{
- static map<string, double> stepUnits;
- if ( stepUnits.empty() ) {
- stepUnits["h"] = 3600;
- stepUnits["s"] = 1;
- stepUnits["m"] = 60;
- stepUnits["3h"] = stepUnits["h"] * 3;
- stepUnits["6h"] = stepUnits["h"] * 6;
- stepUnits["12h"] = stepUnits["h"] * 6;
- stepUnits["D"] = stepUnits["h"] * 24;
- stepUnits["M"] = stepUnits["D"] * 30;
- stepUnits["Y"] = stepUnits["M"] * 12;
- stepUnits["10Y"] = stepUnits["M"] * 10;
- stepUnits["30Y"] = stepUnits["M"] * 30;
- stepUnits["C"] = stepUnits["M"] * 100;
- }
- string units = grib.getString("stepUnits");
- long step = grib.getLong(key);
-
- map<string, double>::iterator stepunit = stepUnits.find(units);
- double factor = 1;
- if ( stepunit != stepUnits.end() )
- factor = stepunit->second;
- return step * factor;
+ static map<string, double> stepUnits;
+ if ( stepUnits.empty() ) {
+ stepUnits["h"] = 3600;
+ stepUnits["s"] = 1;
+ stepUnits["m"] = 60;
+ stepUnits["3h"] = stepUnits["h"] * 3;
+ stepUnits["6h"] = stepUnits["h"] * 6;
+ stepUnits["12h"] = stepUnits["h"] * 6;
+ stepUnits["D"] = stepUnits["h"] * 24;
+ stepUnits["M"] = stepUnits["D"] * 30;
+ stepUnits["Y"] = stepUnits["M"] * 12;
+ stepUnits["10Y"] = stepUnits["M"] * 10;
+ stepUnits["30Y"] = stepUnits["M"] * 30;
+ stepUnits["C"] = stepUnits["M"] * 100;
+ }
+ string units = grib.getString("stepUnits");
+ long step = grib.getLong(key);
+
+ map<string, double>::iterator stepunit = stepUnits.find(units);
+ double factor = 1;
+ if ( stepunit != stepUnits.end() )
+ factor = stepunit->second;
+ return step * factor;
}
long GribDecoder::getLong(const string& key, bool warnIfKeyAbsent) const
{
- long val;
- map<string, long>::const_iterator lk = lKeys_.find(key);
- if ( lk != lKeys_.end() ) {
- return lk->second;
- }
- int err = grib_get_long(handle_, key.c_str(), &val);
- if ( err )
- {
- if (warnIfKeyAbsent)
- {
- MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
- }
- return 0;
- }
- lKeys_.insert(make_pair(key, val));
- return val;
+ long val;
+ map<string, long>::const_iterator lk = lKeys_.find(key);
+ if ( lk != lKeys_.end() ) {
+ return lk->second;
+ }
+ int err = grib_get_long(handle_, key.c_str(), &val);
+ if ( err )
+ {
+ if (warnIfKeyAbsent)
+ {
+ MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
+ }
+ return 0;
+ }
+ lKeys_.insert(make_pair(key, val));
+ return val;
}
string GribDecoder::getstring(const string& key, bool warnIfKeyAbsent, bool cache) const
{
- if ( cache ) {
- map<string, string>::const_iterator sk = sKeys_.find(key);
- if ( sk != sKeys_.end() ) {
- return sk->second;
- }
- }
- char val[1024];
- size_t length = 1024;
-
- int err = grib_get_string(handle_, key.c_str(), val, &length);
-
- if ( err )
- {
- if (warnIfKeyAbsent)
- {
- MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
- }
- return "";
- }
- if ( cache )
- sKeys_.insert(make_pair(key, val));
- return string(val);
+ if ( cache ) {
+ map<string, string>::const_iterator sk = sKeys_.find(key);
+ if ( sk != sKeys_.end() ) {
+ return sk->second;
+ }
+ }
+ char val[1024];
+ size_t length = 1024;
+
+ int err = grib_get_string(handle_, key.c_str(), val, &length);
+
+ if ( err )
+ {
+ if (warnIfKeyAbsent)
+ {
+ MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
+ }
+ return "";
+ }
+ if ( cache )
+ sKeys_.insert(make_pair(key, val));
+ return string(val);
}
string GribDecoder::getString(const string& key, bool warnIfKeyAbsent) const
{
- if ( Data::dimension_ == 1 )
- return getstring(key, warnIfKeyAbsent, false);
-
- string value;
- grib_handle* handle = handle_;
- // otherwise we build a name...
-
- GribDecoder* grib = const_cast<GribDecoder*>(this);
- grib->openFirstComponent();
- string name1 = getstring(key, warnIfKeyAbsent, false);
- grib->openSecondComponent();
- string name2 = getstring(key, warnIfKeyAbsent, false);
- grib->handle(handle);
- value = (name1==name2) ? name1 : name1 + "/" + name2;
-
- if ( Data::dimension_ == 3 ) {
- grib->openThirdComponent();
- string name3 = getstring(key, warnIfKeyAbsent, false);
- grib->handle(handle);
- if ( value != name3 )
- value = value + "/" + name3;
- }
- return value;
+ if ( Data::dimension_ == 1 )
+ return getstring(key, warnIfKeyAbsent, false);
+
+ string value;
+ grib_handle* handle = handle_;
+ // otherwise we build a name...
+
+ GribDecoder* grib = const_cast<GribDecoder*>(this);
+ grib->openFirstComponent();
+ string name1 = getstring(key, warnIfKeyAbsent, false);
+ grib->openSecondComponent();
+ string name2 = getstring(key, warnIfKeyAbsent, false);
+ grib->handle(handle);
+ value = (name1==name2) ? name1 : name1 + "/" + name2;
+
+ if ( Data::dimension_ == 3 ) {
+ grib->openThirdComponent();
+ string name3 = getstring(key, warnIfKeyAbsent, false);
+ grib->handle(handle);
+ if ( value != name3 )
+ value = value + "/" + name3;
+ }
+ return value;
}
double GribDecoder::getDouble(const string& key, bool warnIfKeyAbsent) const
{
- map<string, double>::const_iterator dk = dKeys_.find(key);
- if ( dk != dKeys_.end() ) {
- return dk->second;
- }
- double val;
- int err = grib_get_double(handle_, key.c_str(), &val);
- if ( err )
- {
- if (warnIfKeyAbsent)
- {
- MagLog::warning() << "Grib API: can not find key [" << key << "] - " << grib_get_error_message(err) <<"\n";
- }
- return 0;
- }
- dKeys_.insert(make_pair(key, val));
- return val;
+ map<string, double>::const_iterator dk = dKeys_.find(key);
+ if ( dk != dKeys_.end() ) {
+ return dk->second;
+ }
+ double val;
+ int err = grib_get_double(handle_, key.c_str(), &val);
+ if ( err )
+ {
+ if (warnIfKeyAbsent)
+ {
+ MagLog::warning() << "Grib API: can not find key [" << key << "] - " << grib_get_error_message(err) <<"\n";
+ }
+ return 0;
+ }
+ dKeys_.insert(make_pair(key, val));
+ return val;
}
void GribDecoder::setDouble(const string& key, double val) const
{
- int err = grib_set_double(handle_, key.c_str(), val);
- if ( err )
- {
- MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
- }
+ int err = grib_set_double(handle_, key.c_str(), val);
+ if ( err )
+ {
+ MagLog::warning() << "Grib API: can not find key [" << key << "] - "<< grib_get_error_message(err) <<"\n";
+ }
}
-
-void GribDecoder::read(Matrix **matrix)
+void GribDecoder::scale(const string& metadata, double& scaling, double& offset)
{
+ scaling = 1;
+ offset = 0;
+ if ( metadata.empty() ) {
- if ( handle_ <=0 ) {
- *matrix = 0;
return;
}
- long repres;
- grib_get_long(handle_,"dataRepresentationType",&repres);
- const string representation = getString("typeOfGrid");
+ ParamJSon data = ParamJSon(metadata);
+
+
+ long table = 128; // hard-coded in case of GRIB 2
+ long centre = 98; // hard-coded in case of GRIB 2
+
+ ParamJSon::iterator pid = data.find("paramId");
+
+
+ long id = ( pid != data.end() ) ? tonumber(pid->second) : 0;
try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->interpretAsMatrix(*this, matrix);
- if ( *matrix == 0 ) {
- valid_ = false;
- ostringstream msg;
- msg << "Grib Decoder: Representation [" << representation << "] not yet fully implemented";
- MagLog::error() << msg.str() << std::endl;
- throw MagicsException(msg.str());
- }
-
- interpretor_->scaling(*this, matrix);
+ const ParamDef& paramdef = LocalTable::localInfo(id, table,
+ centre);
+ scaling = paramdef.scaling();
+ offset = paramdef.offset();
+
}
- catch (NoFactoryException&)
- {
- ostringstream msg;
- msg << "Grib Decoder: Representation [" << representation << "] not yet supported";
- MagLog::error() << msg.str() << endl;
- valid_ = false;
- throw MagicsException(msg.str());
+ catch (...) {
+ MagLog::warning()
+ << " Can not find information for the parameter [" << id
+ << "." << table << "]\n";
}
+
+
+}
+
+void GribDecoder::read(Matrix **matrix)
+{
+
+ if ( handle_ <=0 ) {
+ *matrix = 0;
+ return;
+ }
+ long repres;
+ grib_get_long(handle_,"dataRepresentationType",&repres);
+ const string representation = getString("typeOfGrid");
+
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->interpretAsMatrix(*this, matrix);
+ if ( *matrix == 0 ) {
+ valid_ = false;
+ ostringstream msg;
+ msg << "Grib Decoder: Representation [" << representation << "] not yet fully implemented";
+ MagLog::error() << msg.str() << std::endl;
+ throw MagicsException(msg.str());
+ }
+
+ interpretor_->scaling(*this, matrix);
+ }
+ catch (NoFactoryException&)
+ {
+ ostringstream msg;
+ msg << "Grib Decoder: Representation [" << representation << "] not yet supported";
+ MagLog::error() << msg.str() << endl;
+ valid_ = false;
+ throw MagicsException(msg.str());
+ }
}
void GribDecoder::read(Matrix **matrix, const Transformation& transformation)
{
- if ( handle_ <=0 ) {
- *matrix = 0;
- return;
- }
- long repres;
- grib_get_long(handle_,"dataRepresentationType",&repres);
- const string representation = getString("typeOfGrid");
-
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->interpretAsMatrix(*this, matrix, transformation);
- interpretor_->scaling(*this, matrix);
- }
- catch (NoFactoryException&)
- {
- MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- valid_ = false;
- throw MagicsException("Grib Decoder: Representation [] not yet supported.");
- }
+ if ( handle_ <=0 ) {
+ *matrix = 0;
+ return;
+ }
+ long repres;
+ grib_get_long(handle_,"dataRepresentationType",&repres);
+ const string representation = getString("typeOfGrid");
+
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->interpretAsMatrix(*this, matrix, transformation);
+ interpretor_->scaling(*this, matrix);
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ valid_ = false;
+ throw MagicsException("Grib Decoder: Representation [] not yet supported.");
+ }
}
@@ -298,168 +339,168 @@ void GribDecoder::read(Matrix **matrix, const Transformation& transformation)
*/
void GribDecoder::print(ostream& out) const
{
- out << "GribDecoder[";
- GribDecoderAttributes::print(out);
- out << "] ";
+ out << "GribDecoder[";
+ GribDecoderAttributes::print(out);
+ out << "] ";
}
void GribDecoder::release()
{
- if ( matrix_ ) {
- delete matrix_;
- matrix_ = 0;
- }
- if ( xComponent_ ) {
- delete xComponent_;
- xComponent_ = 0;
- }
- if ( yComponent_ ) {
- delete yComponent_;
- yComponent_ = 0;
- }
- if ( colourComponent_ ) {
- delete colourComponent_;
- colourComponent_ = 0;
- }
-
- for (PointsList::iterator point = points_.begin(); point != points_.end(); ++point) {
- delete *point;
- *point = 0;
- }
- points_.clear();
+ if ( matrix_ ) {
+ delete matrix_;
+ matrix_ = 0;
+ }
+ if ( xComponent_ ) {
+ delete xComponent_;
+ xComponent_ = 0;
+ }
+ if ( yComponent_ ) {
+ delete yComponent_;
+ yComponent_ = 0;
+ }
+ if ( colourComponent_ ) {
+ delete colourComponent_;
+ colourComponent_ = 0;
+ }
+
+ for (PointsList::iterator point = points_.begin(); point != points_.end(); ++point) {
+ delete *point;
+ *point = 0;
+ }
+ points_.clear();
}
void GribDecoder::visit(Transformation& transformation)
{
- if(transformation.coordinateType() == Transformation::GeoType )
- return;
- decode();
- // Here are in a dump ode .. the coordinates are pixels.
- if ( transformation.getAutomaticX() ) {
- transformation.setMinMaxX(1, matrix_->columns());
+ if(transformation.coordinateType() == Transformation::GeoType )
+ return;
+ decode();
+ // Here are in a dump ode .. the coordinates are pixels.
+ if ( transformation.getAutomaticX() ) {
+ transformation.setMinMaxX(1, matrix_->columns());
- }
- if ( transformation.getAutomaticY() ) {
- transformation.setMinMaxY(1, matrix_->rows());
+ }
+ if ( transformation.getAutomaticY() ) {
+ transformation.setMinMaxY(1, matrix_->rows());
- }
+ }
}
-void GribDecoder::decode2D()
+void GribDecoder::decode2D()
{
- if (xComponent_) return;
- Matrix *w1 = 0;
- Matrix *w2 = 0;
- colourComponent_ = 0;
- const string representation = getString("typeOfGrid");
- try {
+ if (xComponent_) return;
+ Matrix *w1 = 0;
+ Matrix *w2 = 0;
+ colourComponent_ = 0;
+ const string representation = getString("typeOfGrid");
+ try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->keepOriginal(true);
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->keepOriginal(true);
- }
- catch (NoFactoryException&)
- {
- MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- valid_ = false;
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ valid_ = false;
- }
- readColourComponent();
- openFirstComponent();
- read(&w1);
- openSecondComponent();
- read(&w2);
- Data::dimension_ = ( colourComponent_ ) ? 3 : 2;
+ }
+ readColourComponent();
+ openFirstComponent();
+ read(&w1);
+ openSecondComponent();
+ read(&w2);
+ Data::dimension_ = ( colourComponent_ ) ? 3 : 2;
- wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
- interpretor_->keepOriginal(false);
+ wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
+ interpretor_->keepOriginal(false);
}
void GribDecoder::customisedPoints(const AutomaticThinningMethod& thinning, const Transformation& transformation, const std::set<string>& request, CustomisedPointsList& points)
{
- openFirstComponent();
- long repres;
- grib_get_long(handle_,"dataRepresentationType",&repres);
- const string representation = getString("typeOfGrid");
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
+ openFirstComponent();
+ long repres;
+ grib_get_long(handle_,"dataRepresentationType",&repres);
+ const string representation = getString("typeOfGrid");
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
- // Compute the thinning factor...
+ // Compute the thinning factor...
- double x1 = 0;
- double y1 = 60;
- double x2 = 0;
- double y2 = 60 + interpretor_->XResolution(*this);
+ double x1 = 0;
+ double y1 = 60;
+ double x2 = 0;
+ double y2 = 60 + interpretor_->XResolution(*this);
- UserPoint p1(x1, y1);
- UserPoint p2(x2, y2);
+ UserPoint p1(x1, y1);
+ UserPoint p2(x2, y2);
- double res = transformation.distance(p1, p2);
+ double res = transformation.distance(p1, p2);
- double xstep = ( transformation.getMaxPCX() - transformation.getMinPCX())/ (thinning.x()-1);
- double ystep = ( transformation.getMaxPCY() - transformation.getMinPCY())/ (thinning.y()-1);
+ double xstep = ( transformation.getMaxPCX() - transformation.getMinPCX())/ (thinning.x()-1);
+ double ystep = ( transformation.getMaxPCY() - transformation.getMinPCY())/ (thinning.y()-1);
- int nb = (xstep/res);
+ int nb = (xstep/res);
- xstep = nb * res;
- ystep = int(ystep/res) * res;
+ xstep = nb * res;
+ ystep = int(ystep/res) * res;
- customisedPoints(transformation, points, xstep, ystep, 0);
+ customisedPoints(transformation, points, xstep, ystep, 0);
- }
- catch (NoFactoryException&)
- {
- MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- throw MagicsException("Grib Decoder: Representation [] not yet supported.");
- }
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ throw MagicsException("Grib Decoder: Representation [] not yet supported.");
+ }
}
grib_handle* GribDecoder::uHandle(string& name)
{
- openFirstComponent();
- name = "x_component";
- return handle_;
+ openFirstComponent();
+ name = "x_component";
+ return handle_;
}
grib_handle* GribDecoder::vHandle(string& name)
{
- openSecondComponent();
- name = "y_component";
- return handle_;
+ openSecondComponent();
+ name = "y_component";
+ return handle_;
}
grib_handle* GribDecoder::cHandle(string&)
{
- return 0;
+ return 0;
}
bool compare(const pair<double, double>& pt1, const pair<double, double>& pt2)
{
- if ( pt1.second != pt2.second)
- return false;
+ if ( pt1.second != pt2.second)
+ return false;
- return pt1.second < pt2.second;
+ return pt1.second < pt2.second;
}
@@ -471,53 +512,53 @@ void GribDecoder::newPoint(const Transformation& transformation, double lat, dou
- std::stack<UserPoint> duplicates;
- UserPoint geo(lon, lat);
+ std::stack<UserPoint> duplicates;
+ UserPoint geo(lon, lat);
- transformation.wraparound(geo, duplicates);
- while (duplicates.empty() == false) {
- UserPoint pt = duplicates.top();
- // we try to see if no to near neighborg ...
+ transformation.wraparound(geo, duplicates);
+ while (duplicates.empty() == false) {
+ UserPoint pt = duplicates.top();
+ // we try to see if no to near neighborg ...
- map<double, std::set<double> >::iterator row = positions_.find(pt.y());
- if ( row == positions_.end() )
- positions_.insert(make_pair(pt.y(), std::set<double>()));
- row = positions_.find(pt.y());
- std::set<double>::iterator low = row->second.lower_bound(pt.x());
- bool add = true;
- if ( low != row->second.end() ) {
- double diff = fabs(*low-pt.x());
- if ( diff <= grid )
- add = false;
- ++low;
- if ( low != row->second.end() ) {
- double diff = fabs(*low -pt.x());
- if ( diff <= grid )
- add = false;
- }
- }
- if ( !add ) {
- duplicates.pop();
- continue;
- }
+ map<double, std::set<double> >::iterator row = positions_.find(pt.y());
+ if ( row == positions_.end() )
+ positions_.insert(make_pair(pt.y(), std::set<double>()));
+ row = positions_.find(pt.y());
+ std::set<double>::iterator low = row->second.lower_bound(pt.x());
+ bool add = true;
+ if ( low != row->second.end() ) {
+ double diff = fabs(*low-pt.x());
+ if ( diff <= grid )
+ add = false;
+ ++low;
+ if ( low != row->second.end() ) {
+ double diff = fabs(*low -pt.x());
+ if ( diff <= grid )
+ add = false;
+ }
+ }
+ if ( !add ) {
+ duplicates.pop();
+ continue;
+ }
- row->second.insert(pt.x());
+ row->second.insert(pt.x());
- CustomisedPoint *point = new CustomisedPoint(pt.x(), pt.y(), "");
+ CustomisedPoint *point = new CustomisedPoint(pt.x(), pt.y(), "");
- point->insert(make_pair("x_component", uc));
- point->insert(make_pair("y_component", vc));
- points.push_back(point);
- if ( cc != -9999 ) {
- point->insert(make_pair("colour_component", cc));
+ point->insert(make_pair("x_component", uc));
+ point->insert(make_pair("y_component", vc));
+ points.push_back(point);
+ if ( cc != -9999 ) {
+ point->insert(make_pair("colour_component", cc));
- }
- duplicates.pop();
+ }
+ duplicates.pop();
- }
+ }
}
@@ -525,314 +566,223 @@ void GribDecoder::newPoint(const Transformation& transformation, double lat, dou
struct Compare
{
- template< typename T1, typename T2 >
- bool operator()( T1 const& t1, T2 const& t2 ) const
- {
- return t1.first < t2;
- }
+ template< typename T1, typename T2 >
+ bool operator()( T1 const& t1, T2 const& t2 ) const
+ {
+ return t1.first < t2;
+ }
};
void GribDecoder::customisedPoints(const Transformation& transformation, CustomisedPointsList& out, double thinx, double thiny, double gap)
{
+ // Initialise index and data
+ interpretor_->new_index(*this);
+ uComponent();
+ vComponent();
+ double minlon = interpretor_->west_;
+ double maxlon = interpretor_->east_;
- map<double, map<double, CustomisedPoint*> > data;
-
-
- string xc = "x_component";
- string yc = "y_component";
- string cc = "colour_component";
-
- vector<pair<double, vector<pair<double, CustomisedPoint*> > > > points;
- double minlon, maxlon;
- interpretor_->raw(*this, transformation, points, minlon, maxlon);
- double missing = getDouble("missingValue");
- if ( thinx ) {
- vector<pair<double, double> > positions;
-
- PaperPoint xy = interpretor_->reference(*this, transformation);
-
- transformation.thin(thinx, xy, positions);
- vector<pair<double, double> >::iterator pos = positions.begin();
- out.reserve(positions.size());
-
- if ( points.front().first > points.back().first )
- std::reverse(points.begin(),points.end());
-
- for ( pos = positions.begin(); pos != positions.end(); ++pos) {
- double offset = 0.;
- // First make sure tthat the lon is between the minlon and maxlon.
- double lon = pos->first;
- double lat = pos->second;
- while ( lon < minlon ) {
- lon += 360;
- offset -= 360.;
- }
- while ( lon > maxlon ) {
- lon -= 360.;
- offset += 360.;
- }
- UserPoint ref(lon, lat);
- //cout << "Reference " << ref << endl;
-
- vector<pair<double, vector<pair<double, CustomisedPoint*> > > >::iterator y;
- vector<pair<double, CustomisedPoint*> >::iterator x;
- CustomisedPoint* point = 0;
- if (thinning_debug_) {
- CustomisedPoint* add = new CustomisedPoint(lon, lat, "");
- add->insert(make_pair("x_component", 0.1));
- add->insert(make_pair("y_component", 0.1));
- out.push_back(add);
- }
- y = std::lower_bound(points.begin(), points.end(), lat, Compare());
-
- if ( same(y->first,lat) ) {
-
- x = std::lower_bound(y->second.begin(), y->second.end(), lon, Compare());
- if ( x->first == lon ) {
- point = x->second;
- }
- else {
- UserPoint check(x->first, y->first);
-
- double val = transformation.distance(check, ref);
- double min = val;
- point = x->second;
- //cout << "CHECK1" << check << " -->" << val << endl;
- --x;
- check = UserPoint(x->first, y->first);
- val = transformation.distance( check, ref );
- //cout << "CHECK2" << check << " -->" << val << endl;
- if ( val < min ) {
- min = val;
- point = x->second;
- }
- }
-
- if ( (*point)["x_component"] != missing && (*point)["y_component"] != missing ) {
- CustomisedPoint *add = new CustomisedPoint(point->longitude()+offset, point->latitude(), "");
- pair<double, double> value = (*wind_mode_)((*point)["x_component"], (*point)["y_component"]);
- add->insert(make_pair("x_component", value.first));
- add->insert(make_pair("y_component", value.second));
- //cout << "add " << *add << endl;
- out.push_back(add);
-
- }
- continue;
- }
-
-
- if ( y == points.end() || y == points.begin()) {
- //point is outside!
- continue;
- }
-
-
-
- x = std::lower_bound(y->second.begin(), y->second.end(), lon, Compare());
-
- if ( x == y->second.end() )
- continue;
- if ( x == y->second.begin() && !same(x->first,lon) ) {
- //point is outside!
- continue;
- }
-
- UserPoint check(x->first, y->first);
- double val = transformation.distance(check, ref);
- double min = val;
- //cout << "CHECK3" << check << " -->" << val << endl;
- point = x->second;
- if ( x != y->second.begin() ) {
- --x;
- check = UserPoint(x->first, y->first);
- val = transformation.distance( check, ref );
- //cout << "CHECK4" << check << " -->" << val << endl;
- if ( val < min ) {
- min = val;
- point = x->second;
- }
- }
-
- --y;
- x = std::lower_bound(y->second.begin(), y->second.end(), lon, Compare());
- //cout << "x=" << x->first << endl;
-
-
-
- check = UserPoint(x->first, y->first);
- val = transformation.distance( check, ref );
- //cout << "CHECK5" << check << " -->" << val << endl;
- if ( val < min ) {
- min = val;
- point = x->second;
- }
- if ( x != y->second.begin() ) {
- --x;
- check = UserPoint(x->first, y->first);
- val = transformation.distance( check, ref );
- //cout << "CHECK6" << check << " -->" << val << endl;
- if ( val < min ) {
- min = val;
- point = x->second;
- }
- }
-
- if ( (*point)["x_component"] != missing && (*point)["y_component"] != missing) {
- CustomisedPoint *add = new CustomisedPoint(point->longitude()+offset, point->latitude(), "");
- pair<double, double> value = (*wind_mode_)((*point)["x_component"], (*point)["y_component"]);
-
- add->insert(make_pair("x_component", value.first));
- add->insert(make_pair("y_component", value.second));
- //cout << "add " << *add << endl;
- out.push_back(add);
-
- }
+ double missing = getDouble("missingValue");
- }
+ if ( thinx ) {
+ vector<pair<double, double> > positions;
+ PaperPoint xy = interpretor_->reference(*this, transformation);
+ transformation.thin(thinx, xy, positions);
+ vector<pair<double, double> >::iterator pos = positions.begin();
+ out.reserve(positions.size());
- for ( vector<pair<double, vector<pair<double, CustomisedPoint*> > > >::iterator y = points.begin(); y != points.end(); ++y )
- for ( vector<pair<double, CustomisedPoint*> >::iterator x = y->second.begin(); x != y->second.end(); ++x)
- delete x->second;
- }
- else {
- for ( vector<pair<double, vector<pair<double, CustomisedPoint*> > > >::iterator y = points.begin(); y != points.end(); ++y )
- for ( vector<pair<double, CustomisedPoint*> >::iterator x = y->second.begin(); x != y->second.end(); ++x) {
- CustomisedPoint *point = x->second;
- if ( (*point)["x_component"] != missing && (*point)["y_component"] != missing ) {
- double lon = point->longitude();
- double lat = point->latitude();
- vector<UserPoint> pos;
- transformation.populate(lon, lat, 0, pos);
- for ( vector<UserPoint>::iterator p = pos.begin(); p != pos.end(); ++p) {
- CustomisedPoint *add = new CustomisedPoint(p->x_, p->y_, "");
- pair<double, double> value = (*wind_mode_)((*point)["x_component"], (*point)["y_component"]);
- add->insert(make_pair("x_component", value.first));
- add->insert(make_pair("y_component", value.second));
- out.push_back(add);
- }
- }
- delete point;
-
- }
- }
-}
-void GribDecoder::customisedPoints(const BasicThinningMethod& thinning, const Transformation& transformation, const std::set<string>& needs, CustomisedPointsList& points)
-{
- openFirstComponent();
- long repres;
- grib_get_long(handle_,"dataRepresentationType",&repres);
- const string representation = getString("typeOfGrid");
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- // Compute the thinning factor...
+ int i = 0;
+ for ( pos = positions.begin(); pos != positions.end(); ++pos) {
+ double offset = 0.;
+ // First make sure tthat the lon is between the minlon and maxlon.
+ double lon = pos->first;
+ double lat = pos->second;
- double gap = 0;
- // find the middle point :
- UserPoint ll = transformation.reference();
- PaperPoint xy1 = transformation(ll);
- ll.y_ = ll.y_ + interpretor_->XResolution(*this);
- PaperPoint xy2 = transformation(ll);
+ i++;
+ while ( lon < minlon ) {
+ lon += 360;
+ offset -= 360.;
+ }
+ while ( lon > maxlon ) {
+ lon -= 360.;
+ offset += 360.;
+ }
- gap = xy1.distance(xy2);
- if ( thinning.factor() == 1 ) {
- gap = 0;
- }
- thinning_debug_ = ( needs.find("debug") != needs.end() );
- customisedPoints(transformation, points,
- gap * thinning.factor(),
- gap * thinning.factor(), gap);
+ Index index = interpretor_->nearest(lat, lon);
+ //cout << "[" << lat << ", " << lon << "]-->[" << index.index_ << ", " << index.lat_ << ", " << index.lon_ << "]" << endl;
+ if ( index.index_ != -1 && !index.used_ ) {
+ index.used_ = true;
+ double u = uComponent(index.index_);
+ double v = vComponent(index.index_);
+
+
+ if ( u != missing && v != missing) {
+ CustomisedPoint *add = new CustomisedPoint(index.lon_+offset, index.lat_, "");
+ pair<double, double> value = (*wind_mode_)(u, v);
+
+ add->insert(make_pair("x_component", value.first));
+ add->insert(make_pair("y_component", value.second));
+ out.push_back(add);
+ /* for debug!
+ add = new CustomisedPoint(lon+offset, lat, "");
+
+ add->insert(make_pair("x_component", 0.01));
+ add->insert(make_pair("y_component", 0.01));
+ out.push_back(add);
+ //*/
+ }
+ }
+ }
+ }
+
+
+ else { // no thinning !
+ // get all the points of the index!
+
+ for ( vector<vector<Index> >:: iterator cell = interpretor_->helper_.begin(); cell != interpretor_->helper_.end(); ++cell) {
+ for ( vector<Index>::iterator index = cell->begin(); index != cell->end(); ++index) {
+ double u = uComponent(index->index_);
+ double v = vComponent(index->index_);
+ if ( u != missing && v != missing) {
+ pair<double, double> value = (*wind_mode_)(u, v);
+ vector<UserPoint> pos;
+ transformation.populate(index->lon_, index->lat_, 0, pos);
+ for ( vector<UserPoint>::iterator p = pos.begin(); p != pos.end(); ++p) {
+ CustomisedPoint *add = new CustomisedPoint(p->x(), p->y(), "");
+ add->insert(make_pair("x_component", value.first));
+ add->insert(make_pair("y_component", value.second));
+ out.push_back(add);
+ }
+ }
+
+ }
+ }
+ }
- }
- catch (NoFactoryException&)
- {
- MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- throw MagicsException("Grib Decoder: Representation [] not yet supported.");
- }
}
-void GribDecoder::decode2D(const Transformation&)
-{
- Data::dimension_ = 2;
- if (xComponent_) return;
- Matrix *w1 = 0;
- Matrix *w2 = 0;
+void GribDecoder::customisedPoints(const BasicThinningMethod& thinning, const Transformation& transformation, const std::set<string>& needs, CustomisedPointsList& points)
+{
+ openFirstComponent();
+ long repres;
+ grib_get_long(handle_,"dataRepresentationType",&repres);
+ const string representation = getString("typeOfGrid");
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ // Compute the thinning factor...
- const string representation = getString("typeOfGrid");
+ double gap = 0;
+ // find the middle point :
+ UserPoint ll = transformation.reference();
+ PaperPoint xy1 = transformation(ll);
+ ll.y_ = ll.y_ + interpretor_->XResolution(*this);
+ PaperPoint xy2 = transformation(ll);
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- readColourComponent();
- openFirstComponent();
- read(&w1);
- openSecondComponent();
- read(&w2);
- }
- catch (NoFactoryException&)
- {
- MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- }
- wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
+ gap = xy1.distance(xy2);
+ if ( thinning.factor() == 1 ) {
+ gap = 0;
+
+ }
+ thinning_debug_ = ( needs.find("debug") != needs.end() );
+ customisedPoints(transformation, points,
+ gap * thinning.factor(),
+ gap * thinning.factor(), gap);
+
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ throw MagicsException("Grib Decoder: Representation [] not yet supported.");
+ }
}
+void GribDecoder::decode2D(const Transformation&)
+{
+ Data::dimension_ = 2;
+ if (xComponent_) return;
+ Matrix *w1 = 0;
+ Matrix *w2 = 0;
+
+
-void GribDecoder::openFirstComponent()
+ const string representation = getString("typeOfGrid");
+
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ readColourComponent();
+
+ openFirstComponent();
+ read(&w1);
+ openSecondComponent();
+ read(&w2);
+
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ }
+ wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
+}
+
+
+void GribDecoder::openFirstComponent()
{
- grib_field_position_ = position_1_;
+ grib_field_position_ = position_1_;
- component1_ = open(component1_);
+ component1_ = open(component1_);
}
grib_handle* GribEntryDecoder::open(grib_handle* handle, bool) {
- if ( !handle_ ) {
- return handle_;
- }
- return handle;
+ if ( !handle_ ) {
+ return handle_;
+ }
+ return handle;
}
-void GribDecoder::openSecondComponent()
+void GribDecoder::openSecondComponent()
{
- grib_field_position_ = position_2_;
- component2_ = open(component2_);
+ grib_field_position_ = position_2_;
+ component2_ = open(component2_);
}
void GribDecoder::openThirdComponent()
{
- grib_field_position_ = colour_position_;
- colour_ = open(colour_, false);
+ grib_field_position_ = colour_position_;
+ colour_ = open(colour_, false);
}
void GribDecoder::readColourComponent()
{
- grib_field_position_ = colour_position_;
- try {
- colour_ = open(colour_, false);
- read(&colourComponent_);
- }
+ grib_field_position_ = colour_position_;
+ try {
+ colour_ = open(colour_, false);
+ read(&colourComponent_);
+ }
- catch (...) {
- colourComponent_ = 0;
- valid_ = true;
- }
+ catch (...) {
+ colourComponent_ = 0;
+ valid_ = true;
+ }
@@ -840,147 +790,168 @@ void GribDecoder::readColourComponent()
grib_handle* GribDecoder::open(grib_handle* grib, bool sendmsg)
{
- if ( grib ) {
- handle(grib);
- return grib;
- }
-
+ if ( grib ) {
+ handle(grib);
+ return grib;
+ }
+
+
+ FILE* file = fopen(file_name_.c_str(),"r");
+ handle_ = 0;
+ if (!file)
+ {
+ MagLog::error() << "file can not be opened [" << file_name_ << "]" << std::endl;
+ MagLog::broadcast();
+ valid_ = false;
+ return 0;
+ }
+
+ handle_ = (*address_mode_)(0, file, grib_field_position_);
+
+ if (handle_<=0 )
+ {
+ if (sendmsg) {
+ MagLog::error() << "can not access position [" << grib_field_position_<<" in " << file_name_ << "]" << std::endl;
+ MagLog::broadcast();
+ valid_ = false;
+ return 0;
+ }
+ }
+ fclose(file);
- FILE* file = fopen(file_name_.c_str(),"r");
- handle_ = 0;
- if (!file)
- {
- MagLog::error() << "file can not be opened [" << file_name_ << "]" << std::endl;
- MagLog::broadcast();
- valid_ = false;
- return 0;
- }
+ return handle_;
+}
- handle_ = (*address_mode_)(0, file, grib_field_position_);
- if (handle_<=0 )
- {
- if (sendmsg) {
- MagLog::error() << "can not access position [" << grib_field_position_<<" in " << file_name_ << "]" << std::endl;
- MagLog::broadcast();
- valid_ = false;
- return 0;
- }
- }
- fclose(file);
+grib_nearest* GribDecoder::nearest_point_handle(bool keep)
+{
+ int err;
- return handle_;
+ if (!keep)
+ {
+ return grib_nearest_new(handle_, &err); // create a new one
+ }
+ else
+ { // we want to retain this and only create a new one if needed
+ if (!nearest_)
+ {
+ nearest_ = grib_nearest_new(handle_, &err); // only used in Metview's Cursor Data facility
+ if (err)
+ return 0;
+ }
+ return nearest_;
+ }
}
bool GribDecoder::id(const string& id, const string& where) const
{
- if ( id_.empty() && id.empty() ){
+ if ( id_.empty() && id.empty() ){
- return ( verify(where) );
- }
- return magCompare(id_, id);
+ return ( verify(where) );
+ }
+ return magCompare(id_, id);
}
bool GribDecoder::verify(const string& val) const
{
- // we except a string with the following format "key1=val,key2=val2,...,keyn=valn"
- Tokenizer tokenizer(",= ");
- vector<string> tokens;
- map<string, string> where;
- tokenizer(val, tokens);
- vector<string>::iterator token = tokens.begin();
-
- string key, value;
- while (true) {
- if (token == tokens.end() )
- break;
- key = *token;
- ++token;
- if (token == tokens.end() )
- break;
- value = *token;
- where.insert(make_pair(key, value));
-
- ++token;
- }
- for ( map<string, string>::const_iterator w = where.begin(); w != where.end(); ++w) {
- string val = getString(w->first);
- if ( magCompare(val, w->second) == false )
- return false;
- }
- return true;
+ // we except a string with the following format "key1=val,key2=val2,...,keyn=valn"
+ Tokenizer tokenizer(",= ");
+ vector<string> tokens;
+ map<string, string> where;
+ tokenizer(val, tokens);
+ vector<string>::iterator token = tokens.begin();
+
+ string key, value;
+ while (true) {
+ if (token == tokens.end() )
+ break;
+ key = *token;
+ ++token;
+ if (token == tokens.end() )
+ break;
+ value = *token;
+ where.insert(make_pair(key, value));
+
+ ++token;
+ }
+ for ( map<string, string>::const_iterator w = where.begin(); w != where.end(); ++w) {
+ string val = getString(w->first);
+ if ( magCompare(val, w->second) == false )
+ return false;
+ }
+ return true;
}
void GribDecoder::decodePoints()
{
- if ( !points_.empty() ) return;
- unsigned long flags=0;
- int error;
-
- if ( Data::dimension_ == 1 ) {
- double scaling;
- double offset;
- field_ = open(field_);
- const string representation = getString("typeOfGrid");
- double missing = getDouble("missingValue");
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->scaling(*this, scaling, offset);
- }
- catch (NoFactoryException&)
- {
- MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- scaling =1 ; offset =0;
- }
-
- grib_iterator* iter = grib_iterator_new(handle_, flags, &error);
-
-
-
- if (!iter)
- {
- MagLog::error() << "Grib Iterator not yet supported on this kind of grib\n";
- MagLog::broadcast();
- throw MagicsException("Grib Iterator not yet supported.");
- }
-
- double lat;
- double lon;
- double val;
- while (grib_iterator_next(iter,&lat,&lon,&val))
- {
- if ( val != missing)
- points_.push_back(new UserPoint(lon, lat, (val*scaling) + offset));
- }
- return;
- }
+ if ( !points_.empty() ) return;
+ unsigned long flags=0;
+ int error;
+
+ if ( Data::dimension_ == 1 ) {
+ double scaling;
+ double offset;
+ field_ = open(field_);
+ const string representation = getString("typeOfGrid");
+ double missing = getDouble("missingValue");
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->scaling(*this, scaling, offset);
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ scaling =1 ; offset =0;
+ }
- openFirstComponent();
- const string representation = getString("typeOfGrid");
- double missing = getDouble("missingValue");
-
- grib_iterator* iter1 = grib_iterator_new(handle_, flags, &error);
- openSecondComponent();
- grib_iterator* iter2 = grib_iterator_new(handle_, flags, &error);
- if (!iter1 || !iter2)
- {
- MagLog::error() << "Grib Iterator not yet supported on this kind of grib\n";
- throw MagicsException("Grib Iterator not yet supported.");
- }
+ grib_iterator* iter = grib_iterator_new(handle_, flags, &error);
- double lat1, lat2;
- double lon1, lon2;
- double val1, val2, norm;
- while ( grib_iterator_next(iter1,&lat1,&lon1,&val1) && grib_iterator_next(iter2,&lat2,&lon2,&val2) )
- {
- if ( lat1 == lat2 && lon1 == lon2 )
- if ( val1 != missing && val2 != missing) {
- norm=wind_mode_->norm(val1,val2);
- points_.push_back(new UserPoint(lon1, lat1, norm));
- }
- }
+
+
+ if (!iter)
+ {
+ MagLog::error() << "Grib Iterator not yet supported on this kind of grib\n";
+ MagLog::broadcast();
+ throw MagicsException("Grib Iterator not yet supported.");
+ }
+
+ double lat;
+ double lon;
+ double val;
+ while (grib_iterator_next(iter,&lat,&lon,&val))
+ {
+ if ( val != missing)
+ points_.push_back(new UserPoint(lon, lat, (val*scaling) + offset));
+ }
+ return;
+ }
+
+ openFirstComponent();
+ const string representation = getString("typeOfGrid");
+ double missing = getDouble("missingValue");
+
+ grib_iterator* iter1 = grib_iterator_new(handle_, flags, &error);
+ openSecondComponent();
+ grib_iterator* iter2 = grib_iterator_new(handle_, flags, &error);
+ if (!iter1 || !iter2)
+ {
+ MagLog::error() << "Grib Iterator not yet supported on this kind of grib\n";
+ throw MagicsException("Grib Iterator not yet supported.");
+ }
+
+ double lat1, lat2;
+ double lon1, lon2;
+ double val1, val2, norm;
+ while ( grib_iterator_next(iter1,&lat1,&lon1,&val1) && grib_iterator_next(iter2,&lat2,&lon2,&val2) )
+ {
+ if ( lat1 == lat2 && lon1 == lon2 )
+ if ( val1 != missing && val2 != missing) {
+ norm=wind_mode_->norm(val1,val2);
+ points_.push_back(new UserPoint(lon1, lat1, norm));
+ }
+ }
}
@@ -989,16 +960,22 @@ void GribDecoder::decodePoints()
GribLoop::~GribLoop()
{
- for (vector<GribDecoder*>::const_iterator g = gribs_.begin(); g != gribs_.end(); ++g)
- {
- delete *g;
- }
+ for (vector<GribDecoder*>::const_iterator g = gribs_.begin(); g != gribs_.end(); ++g)
+ {
+ delete *g;
+ }
+
+ if (file_ != 0)
+ {
+ fclose(file_);
+ file_ = 0;
+ }
}
Data* GribLoop::current()
{
- return currentgrib_;
+ return currentgrib_;
}
@@ -1009,18 +986,18 @@ void GribLoop::next() {}
GribLoop::GribLoop(): currentgrib_(0), file_(0)
{
- currentDim_ = dimension_.begin();
- currentPos_ = dim_.begin();
- gribs_.clear();
- uniqueId_ = Data::getUniqueOwnerId();
- counter_ = 0;
+ currentDim_ = dimension_.begin();
+ currentPos_ = dim_.begin();
+ gribs_.clear();
+ uniqueId_ = Data::getUniqueOwnerId();
+ counter_ = 0;
}
-void GribLoop::setToFirst()
+void GribLoop::setToFirst()
{
- currentDim_ = dimension_.begin();
- currentPos_ = dim_.begin();
+ currentDim_ = dimension_.begin();
+ currentPos_ = dim_.begin();
}
@@ -1028,831 +1005,899 @@ void GribLoop::setToFirst()
bool GribLoop::hasMore()
{
- if (file_ == 0 ) {
- file_ = fopen(path_.c_str(),"r");
- if (!file_) {
- MagLog::error() << "file can not be opened [" << path_ << "]" << std::endl;
- throw GribFileMagException(path_, 0);
- }
- }
-
-
+ if (file_ == 0 ) {
+ file_ = fopen(path_.c_str(),"r");
+ if (!file_) {
+ MagLog::error() << "file can not be opened [" << path_ << "]" << std::endl;
+ throw GribFileMagException(path_, 0);
+ }
+ }
- // Now we have to find the right Entry!!!
- if ( currentDim_ == dimension_.end() )
- return false;
+ // Now we have to find the right Entry!!!
- if ( *currentDim_ == 1 ) {
- if ( dim_.empty() ) {
- // case 1 dimension= 1 and loop on all the fields!
- int error;
- grib_handle* handle = grib_handle_new_from_file(0, file_, &error) ;
- if (handle <=0)
- return false;
- currentgrib_ = new GribEntryDecoder(handle);
+ if ( currentDim_ == dimension_.end() )
+ return false;
- currentgrib_->set(*this, counter_++);
- gribs_.push_back(currentgrib_);
- }
- else {
- if ( currentPos_ == dim_.end() )
- return false;
- // Case 3 Dimension = 1 but we only used a subset of fields
+ if ( *currentDim_ == 1 ) {
+ if ( dim_.empty() ) {
+ // case 1 dimension= 1 and loop on all the fields!
+ int error;
+ grib_handle* handle = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle <=0)
+ return false;
+ currentgrib_ = new GribEntryDecoder(handle);
- grib_handle* handle = (*address_mode_)(0, file_, *currentPos_);
- currentPos_++;
- if (handle <=0)
- return false;
- currentgrib_ = new GribEntryDecoder(handle);
- currentgrib_->set(*this, counter_++);
- gribs_.push_back(currentgrib_);
- }
- }
+ currentgrib_->set(*this, counter_++);
+ gribs_.push_back(currentgrib_);
+ }
+ else {
+ if ( currentPos_ == dim_.end() )
+ return false;
+ // Case 3 Dimension = 1 but we only used a subset of fields
+
+ grib_handle* handle = (*address_mode_)(0, file_, *currentPos_);
+ currentPos_++;
+ if (handle <=0)
+ return false;
+ currentgrib_ = new GribEntryDecoder(handle);
+ currentgrib_->set(*this, counter_++);
+ gribs_.push_back(currentgrib_);
+ }
+ }
+
+
+ if ( *currentDim_ == 2)
+ {
+ if ( dim_.empty() )
+ {
+ // case 2 Dimension = 2 and loop on all the field!
+ int error;
+ grib_handle* handle1 = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle1 <=0) return false;
+ grib_handle* handle2 = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle2 <=0) return false;
+ currentgrib_ = new GribEntryDecoder(handle1, handle2);
+ currentgrib_->set(*this, counter_++);
+ gribs_.push_back(currentgrib_);
+ }
+ else {
+ // Case 4 Dimesnion = 2 and we only used a subset of fields!
+ vector<long int>::iterator dim1 = currentPos_;
+ if ( currentPos_ == dim_.end() )
+ return false;
+ currentPos_++;
+ vector<long int>::iterator dim2 = currentPos_;
+ if ( currentPos_ == dim_.end() )
+ return false;
+ currentPos_++;
+
+
+ grib_handle* handle1 = (*address_mode_)(0, file_, *dim1);
+ grib_handle* handle2 = (*address_mode_)(0, file_, *dim2);
+ if ( handle1 <=0 )
+ return false;
+ if ( handle2 <=0 )
+ return false;
+ currentgrib_ = new GribEntryDecoder(handle1, handle2);
+ currentgrib_->set(*this, counter_++);
+
+ gribs_.push_back(currentgrib_);
- if ( *currentDim_ == 2)
- {
- if ( dim_.empty() )
- {
- // case 2 Dimension = 2 and loop on all the field!
- int error;
- grib_handle* handle1 = grib_handle_new_from_file(0, file_, &error) ;
- if (handle1 <=0) return false;
- grib_handle* handle2 = grib_handle_new_from_file(0, file_, &error) ;
- if (handle2 <=0) return false;
- currentgrib_ = new GribEntryDecoder(handle1, handle2);
- currentgrib_->set(*this, counter_++);
- gribs_.push_back(currentgrib_);
- }
- else {
- // Case 4 Dimesnion = 2 and we only used a subset of fields!
- vector<int>::iterator dim1 = currentPos_;
- if ( currentPos_ == dim_.end() )
- return false;
- currentPos_++;
- vector<int>::iterator dim2 = currentPos_;
- if ( currentPos_ == dim_.end() )
- return false;
- currentPos_++;
-
-
- grib_handle* handle1 = (*address_mode_)(0, file_, *dim1);
- grib_handle* handle2 = (*address_mode_)(0, file_, *dim2);
- if ( handle1 <=0 )
- return false;
- if ( handle2 <=0 )
- return false;
- currentgrib_ = new GribEntryDecoder(handle1, handle2);
- currentgrib_->set(*this, counter_++);
-
- gribs_.push_back(currentgrib_);
-
- }
- }
+ }
+ }
+
+ if ( *currentDim_ == 3)
+ {
+ if ( dim_.empty() )
+ {
+ // case 2 Dimension = 2 and loop on all the field!
+ int error;
+ grib_handle* handle1 = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle1 <=0) return false;
+ grib_handle* handle2 = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle2 <=0) return false;
+ grib_handle* handle3 = grib_handle_new_from_file(0, file_, &error) ;
+ if (handle3 <=0) return false;
+ currentgrib_ = new GribEntryDecoder(handle1, handle2, handle3);
+ currentgrib_->set(*this, counter_++);
+ gribs_.push_back(currentgrib_);
+ }
+ else {
+ // Case 4 Dimesnion = 2 and we only used a subset of fields!
+ vector<long int>::iterator dim1 = currentPos_;
+ if ( currentPos_ == dim_.end() )
+ return false;
+ currentPos_++;
+ vector<long int>::iterator dim2 = currentPos_;
+ if ( currentPos_ == dim_.end() )
+ return false;
+ currentPos_++;
+ vector<long int>::iterator dim3 = currentPos_;
+ if ( currentPos_ == dim_.end() )
+ return false;
+ currentPos_++;
+
+ grib_handle* handle1 = (*address_mode_)(0, file_, *dim1);
+ grib_handle* handle2 = (*address_mode_)(0, file_, *dim2);
+ grib_handle* handle3 = (*address_mode_)(0, file_, *dim3);
+
+ if ( handle1 <=0 )
+ return false;
+ if ( handle2 <=0 )
+ return false;
+ if ( handle3 <=0 )
+ return false;
+ currentgrib_ = new GribEntryDecoder(handle1, handle2, handle3);
+ currentgrib_->set(*this, counter_++);
+
+ gribs_.push_back(currentgrib_);
- if ( *currentDim_ == 3)
- {
- if ( dim_.empty() )
- {
- // case 2 Dimension = 2 and loop on all the field!
- int error;
- grib_handle* handle1 = grib_handle_new_from_file(0, file_, &error) ;
- if (handle1 <=0) return false;
- grib_handle* handle2 = grib_handle_new_from_file(0, file_, &error) ;
- if (handle2 <=0) return false;
- grib_handle* handle3 = grib_handle_new_from_file(0, file_, &error) ;
- if (handle3 <=0) return false;
- currentgrib_ = new GribEntryDecoder(handle1, handle2, handle3);
- currentgrib_->set(*this, counter_++);
- gribs_.push_back(currentgrib_);
- }
- else {
- // Case 4 Dimesnion = 2 and we only used a subset of fields!
- vector<int>::iterator dim1 = currentPos_;
- if ( currentPos_ == dim_.end() )
- return false;
- currentPos_++;
- vector<int>::iterator dim2 = currentPos_;
- if ( currentPos_ == dim_.end() )
- return false;
- currentPos_++;
- vector<int>::iterator dim3 = currentPos_;
- if ( currentPos_ == dim_.end() )
- return false;
- currentPos_++;
-
- grib_handle* handle1 = (*address_mode_)(0, file_, *dim1);
- grib_handle* handle2 = (*address_mode_)(0, file_, *dim2);
- grib_handle* handle3 = (*address_mode_)(0, file_, *dim3);
-
- if ( handle1 <=0 )
- return false;
- if ( handle2 <=0 )
- return false;
- if ( handle3 <=0 )
- return false;
- currentgrib_ = new GribEntryDecoder(handle1, handle2, handle3);
- currentgrib_->set(*this, counter_++);
-
- gribs_.push_back(currentgrib_);
-
- }
- }
- currentDim_++;
- currentgrib_->setPath(path_);
- if ( iconName_.empty() )
- {
- map<string, string>::iterator id = ids_.find(path_);
- if ( id == ids_.end() )
- {
- iconName_ = "Grib" + tostring(index_);
- index_++;
- ids_.insert(make_pair(path_, iconName_));
- }
- else
- iconName_ = id->second;
- }
- currentgrib_->icon(*this);
- return true;
+ }
+ }
+ currentDim_++;
+ currentgrib_->setPath(path_);
+ if ( iconName_.empty() )
+ {
+ map<string, string>::iterator id = ids_.find(path_);
+ if ( id == ids_.end() )
+ {
+ iconName_ = "Grib" + tostring(index_);
+ index_++;
+ ids_.insert(make_pair(path_, iconName_));
+ }
+ else
+ iconName_ = id->second;
+ }
+ currentgrib_->icon(*this);
+ return true;
}
void GribLoop::print(ostream&) const {}
void GribDecoder::handle(grib_handle* handle)
{
- handle_ = handle;
- lKeys_.clear();
- sKeys_.clear();
- dKeys_.clear();
+ handle_ = handle;
+ lKeys_.clear();
+ sKeys_.clear();
+ dKeys_.clear();
}
class GribTag: public XmlNodeVisitor
{
public:
- GribTag(GribDecoder& grib, TagHandler& title) : grib_(grib), title_(title) {
- }
-
- ~GribTag() {}
- string baseDate(const XmlNode& node)
- {
- string format= node.getAttribute("format");
- if ( format.empty() )
- format = "%A %d %B %Y %H%M UTC";
- const long day = grib_.getLong("date");
- const long hour = grib_.getLong("hour");
- const long mn = grib_.getLong("minute");
- MagDate part1 = MagDate(day);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
-
- const long type = grib_.getLong("significanceOfReferenceTime", false);
+ GribTag(GribDecoder& grib, TagHandler& title) : grib_(grib), title_(title) {
+ }
+
+ ~GribTag() {}
+ string baseDate(const XmlNode& node)
+ {
+ string format= node.getAttribute("format");
+ if ( format.empty() )
+ format = "%A %d %B %Y %H%M UTC";
+ const long day = grib_.getLong("date");
+ const long hour = grib_.getLong("hour");
+ const long mn = grib_.getLong("minute");
+ MagDate part1 = MagDate(day);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+
+ const long type = grib_.getLong("significanceOfReferenceTime", false);
if ( type == 2 ) { // Verifying time of forecast
- const long step = computeStep(grib_, "stepRange");
+ const long step = computeStep(grib_, "stepRange");
full = full + (step * -1);
}
- return full.tostring(format);
+ return full.tostring(format);
- }
+ }
- string startDate(const XmlNode& node)
- {
- string format= node.getAttribute("format");
- if ( format.empty() )
- format = "%A %d %B %Y %H%M UTC";
- const long day = grib_.getLong("date");
- const long hour = grib_.getLong("hour");
- const long mn = grib_.getLong("minute");
- const long step = computeStep(grib_, "startStep");
-
- MagDate part1 = MagDate(day);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
- full = full + step;
-
- return full.tostring(format);
- }
+ string startDate(const XmlNode& node)
+ {
+ string format= node.getAttribute("format");
+ if ( format.empty() )
+ format = "%A %d %B %Y %H%M UTC";
+ const long day = grib_.getLong("date");
+ const long hour = grib_.getLong("hour");
+ const long mn = grib_.getLong("minute");
+ const long step = computeStep(grib_, "startStep");
- string validDate(const XmlNode& node)
- {
- string format= node.getAttribute("format");
- if ( format.empty() )
- format = "%A %d %B %Y %H%M UTC";
- const long day = grib_.getLong("date");
- const long hour = grib_.getLong("hour");
- const long mn = grib_.getLong("minute");
- const long step = computeStep(grib_, "stepRange"); // default is in hours. Set 'stepUnits' to change.
+ MagDate part1 = MagDate(day);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+ full = full + step;
+ return full.tostring(format);
+ }
+ string validDate(const XmlNode& node)
+ {
+ string format= node.getAttribute("format");
+ if ( format.empty() )
+ format = "%A %d %B %Y %H%M UTC";
+ const long day = grib_.getLong("date");
+ const long hour = grib_.getLong("hour");
+ const long mn = grib_.getLong("minute");
+ const long step = computeStep(grib_, "stepRange"); // default is in hours. Set 'stepUnits' to change.
- MagDate part1 = MagDate(day);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
- const long type = grib_.getLong("significanceOfReferenceTime", false);
- if ( type != 2 ) { // Verifying time of forecast
- full = full + step;
- }
- return full.tostring(format);
- }
+ MagDate part1 = MagDate(day);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+ const long type = grib_.getLong("significanceOfReferenceTime", false);
+ if ( type != 2 ) { // Verifying time of forecast
+ full = full + step;
+ }
- string endDate(const XmlNode& node)
- {
- string format= node.getAttribute("format");
- if ( format.empty() )
- format = "%A %d %B %Y %H%M UTC";
- const long day = grib_.getLong("date");
- const long hour = grib_.getLong("hour");
- const long mn = grib_.getLong("minute");
- const long step = computeStep(grib_, "endStep");
+ return full.tostring(format);
+
+ }
+
+ string endDate(const XmlNode& node)
+ {
+ string format= node.getAttribute("format");
+ if ( format.empty() )
+ format = "%A %d %B %Y %H%M UTC";
+ const long day = grib_.getLong("date");
+ const long hour = grib_.getLong("hour");
+ const long mn = grib_.getLong("minute");
+ const long step = computeStep(grib_, "endStep");
+
+ MagDate part1 = MagDate(day);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+ full = full + step;
+
+ return full.tostring(format);
+
+ }
+
+
+
+ void visit(const XmlNode& node)
+ {
+ if ( magCompare(node.name(), "grib_info") )
+ {
+ string grib = node.getAttribute("id");
+ string where = node.getAttribute("where");
+ if ( !grib_.id(grib, where)) {
+
+ return;
+ }
+ string def = node.getAttribute("key");
+ if (def.empty()) {
+ def = node.getAttribute("definition");
+ // for backward compatibility with the first version!
+ }
+ if ( def== "valid-date") {
+ title_.update("grib"+grib, def, validDate(node));
+ return;
+ }
+
+ if ( def == "base-date") {
+ title_.update("grib"+grib, def, baseDate(node));
+ return;
+ }
+ if ( def == "MV_Format" ) {
+ title_.update("grib"+grib, def, "grib");
+ return;
+ }
+ if ( def == "MV_Index" || def == "MV_Frame" || def == "MV_Value" ) {
+ // this is handled by Metview, so we just ignore it here
+ return;
+ }
+ if ( def == "start-date" ) {
+ title_.update("grib"+grib, def, startDate(node));
+ return;
+ }
+ if ( def == "end-date" ) {
+ title_.update("grib"+grib, def, endDate(node));
+ return;
+ }
+ string val;
+ string readAsLong = node.getAttribute("readAsLong");
+ if(readAsLong != "yes")
+ {
+ val = grib_.getString(def);
+ string format = node.getAttribute("format");
+ if ( !format.empty() ) {
+ char tmp[256];
+ sprintf(tmp, format.c_str(), val.c_str());
+ val = tmp;
+
+ }
+ }
+ else
+ {
+ long longVal = grib_.getLong(def);
+ std::stringstream sst ;
+ sst << longVal;
+ val=sst.str();
+ }
+
+ if ( val.empty() )
+ val = node.getAttribute("default");
+ title_.update("grib"+grib, def, val);
+ }
- MagDate part1 = MagDate(day);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
- full = full + step;
+ if ( magCompare(node.name(), "magics_title") )
+ {
+ string grib = node.getAttribute("id");
+ string where = node.getAttribute("where");
+ if ( !grib_.id(grib, where)) return;
+
+ vector<string> lines;
+ TitleTemplate::title(lines, grib_);
+ for (unsigned int i = 0; i < lines.size(); i++)
+ {
+ string id = grib_.title() + "_" + tostring(i);
+ title_.update("grib"+grib, id, lines[i]);
+ string entry = "<grib_info definition=\'" + id + "\'/>";
+ title_.addToTags("<magics_title/>", entry);
+ }
+ //title_.addLines(lines.size());
+ }
+ node.visit(*this);
+ }
+
+ void decode(const string& line)
+ {
+ XmlReader parser;
+ XmlTree tree;
+
+ ostringstream xml;
+ xml << "<?xml version='1.0' ?> \n";
+ xml << "<xml> \n";
+ xml << line;
+ xml << "\n</xml>";
+
+ try {
+ parser.decode(xml.str(), &tree);
+ tree.visit(*this);
+ }
+ catch (MagicsException& e) {
+ MagLog::debug() << e.what() << endl;
+ }
+ }
+ string str() const { return out.str(); }
+protected :
+ GribDecoder& grib_;
+ TagHandler& title_;
+ ostringstream out;
+};
- return full.tostring(format);
+void GribDecoder::visit(AnimationRules& )
+{
+}
- }
+// GribDecoder::nearestGridpoints
+// For a list of input gridpoint locations, returns the locations and values for the closest actual data
+// point to each.
+// Note that we cannot yet apply the same method to all grid types because there is a bug in GRIB_API versions
+// prior to 1.15.0 which means that grib_nearest_find() does not work with Lambert grids when we keep the
+// same grib_nearest object.
+void GribDecoder::nearestGridpoints(double *inlats, double *inlons, double *outlats, double *outlons, double *values, double *distances, int nb, string &representation)
+{
+ bool retainGribNearestHandle = false;
+ grib_nearest *nearHandle = NULL;
+ double outlats4[4]; // grib_nearest_find returns 4 results
+ double outlons4[4]; // grib_nearest_find returns 4 results
+ double outvals4[4]; // grib_nearest_find returns 4 results
+ double outdist4[4]; // grib_nearest_find returns 4 results
+ int outindexes[4]; // grib_nearest_find returns 4 results
+ size_t len;
+
+ if (representation == "regular_ll" ||
+ representation == "reduced_ll" ||
+ representation == "regular_gg" ||
+ representation == "reduced_gg")
+ {
+ retainGribNearestHandle = true; // more efficient
+ }
+
+
+ nearHandle = nearest_point_handle(retainGribNearestHandle);
+
+
+
+ for (int i=0; i < nb; i++)
+ {
+ if (nearHandle)
+ {
+ grib_nearest_find(nearHandle, handle_, inlats[i], inlons[i], GRIB_NEAREST_SAME_GRID, outlats4, outlons4,
+ outvals4, outdist4, outindexes, &len);
+ vector<double> vdistances(outdist4, outdist4+4);
+ int closestIndex = distance(vdistances.begin(), min_element(vdistances.begin(), vdistances.end()));
+ outlats[i] = outlats4[closestIndex];
+ outlons[i] = outlons4[closestIndex];
+ values[i] = outvals4[closestIndex];
+ distances[i] = outdist4[closestIndex];
+ }
+ else
+ {
+ outlats[i] = 0;
+ outlons[i] = 0;
+ values[i] = 0;
+ distances[i] = 0;
+ }
+// grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, values, distances, indexes);
+// int closestIndex = 0;
+ }
- void visit(const XmlNode& node)
- {
- if ( magCompare(node.name(), "grib_info") )
- {
- string grib = node.getAttribute("id");
- string where = node.getAttribute("where");
- if ( !grib_.id(grib, where)) {
-
- return;
- }
- string def = node.getAttribute("key");
- if (def.empty()) {
- def = node.getAttribute("definition");
- // for backward compatibility with the first version!
- }
- if ( def== "valid-date") {
- title_.update("grib"+grib, def, validDate(node));
- return;
- }
-
- if ( def == "base-date") {
- title_.update("grib"+grib, def, baseDate(node));
- return;
- }
- if ( def == "MV_Format" ) {
- title_.update("grib"+grib, def, "grib");
- return;
- }
- if ( def == "MV_Index" || def == "MV_Frame" || def == "MV_Value" ) {
- // this is handled by Metview, so we just ignore it here
- return;
- }
- if ( def == "start-date" ) {
- title_.update("grib"+grib, def, startDate(node));
- return;
- }
- if ( def == "end-date" ) {
- title_.update("grib"+grib, def, endDate(node));
- return;
- }
- string val;
- string readAsLong = node.getAttribute("readAsLong");
- if(readAsLong != "yes")
- {
- val = grib_.getString(def);
- string format = node.getAttribute("format");
- if ( !format.empty() ) {
- char tmp[256];
- sprintf(tmp, format.c_str(), val.c_str());
- val = tmp;
-
- }
- }
- else
- {
- long longVal = grib_.getLong(def);
- std::stringstream sst ;
- sst << longVal;
- val=sst.str();
- }
-
- if ( val.empty() )
- val = node.getAttribute("default");
- title_.update("grib"+grib, def, val);
- }
-
- if ( magCompare(node.name(), "magics_title") )
- {
- string grib = node.getAttribute("id");
- string where = node.getAttribute("where");
- if ( !grib_.id(grib, where)) return;
-
- vector<string> lines;
- TitleTemplate::title(lines, grib_);
- for (unsigned int i = 0; i < lines.size(); i++)
- {
- string id = grib_.title() + "_" + tostring(i);
- title_.update("grib"+grib, id, lines[i]);
- string entry = "<grib_info definition=\'" + id + "\'/>";
- title_.addToTags("<magics_title/>", entry);
- }
- //title_.addLines(lines.size());
- }
- node.visit(*this);
- }
- void decode(const string& line)
- {
- XmlReader parser;
- XmlTree tree;
-
- ostringstream xml;
- xml << "<?xml version='1.0' ?> \n";
- xml << "<xml> \n";
- xml << line;
- xml << "\n</xml>";
-
- try {
- parser.decode(xml.str(), &tree);
- tree.visit(*this);
- }
- catch (MagicsException& e) {
- MagLog::debug() << e.what() << endl;
- }
- }
- string str() const { return out.str(); }
-protected :
- GribDecoder& grib_;
- TagHandler& title_;
- ostringstream out;
-};
+ if (!retainGribNearestHandle && nearHandle) // was this a temporary handle?
+ grib_nearest_delete(nearHandle);
-void GribDecoder::visit(AnimationRules& )
-{
}
void GribDecoder::visit(ValuesCollector& points)
{
- field_ = open(field_);
- const Transformation& transformation = points.transformation();
-
- points.setCollected(true);
-
- int nb = points.size();
- double inlats[nb];
- double inlons[nb];
- double outlats[nb];
- double outlons[nb];
- double values[nb];
- double x[nb];
- double y[nb];
- double distances[nb];
- int indexes[nb];
- double scaling, offset;
- string oriUnits, derivedUnits;
- string representation = getString("typeOfGrid");
-
- //Scaling works only for scalar data!!!
-
- try
- {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->scaling(*this, scaling, offset,oriUnits,derivedUnits);
- }
- catch (NoFactoryException&)
- {
- MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- scaling =1 ; offset =0;
- }
+ field_ = open(field_);
- for (int i =0; i < nb; i++)
- {
- inlats[i] = points[i].y();
- inlons[i] = std::fmod(points[i].x(),360.);
- if(inlons[i] < 0.) inlons[i]+=360.;
- i++;
- }
+ points.setCollected(true);
- double missing = getDouble("missingValue");
-
- if ( Data::dimension_ == 1 ) {
- bool scaled=(scaling==1 && offset == 0)?false:true;
- points.setScaled(scaled);
- points.setUnits(oriUnits);
- points.setScaledUnits(derivedUnits);
-
- field_ = open(field_);
- grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, values, distances, indexes);
- for (int i =0; i < nb; i++)
- {
- points[i].push_back(new ValuesCollectorData(outlons[i],outlats[i],values[i],distances[i]));
- if(scaled)
- points[i].back()->setScaledValue(scaling*values[i] + offset);
- if(values[i] == missing)
- points[i].back()->setMissing(true);
- }
- }
- else if ( Data::dimension_ == 2 ) {
- bool scaled=(scaling==1 && offset == 0)?false:true;
- oriUnits=getString("units",false);
- if(oriUnits.find("/") == string::npos)
- {
- oriUnits=oriUnits + "/" + oriUnits;
- }
- points.setUnits(oriUnits);
- points.setScaledUnits("/");
-
-
- openFirstComponent();
- grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, x, distances, indexes);
- openSecondComponent();
- grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, y, distances, indexes);
- for (int i =0; i < nb; i++)
- {
- points[i].push_back(wind_mode_->values(outlons[i],outlats[i],x[i],y[i], distances[i]));
- if(x[i] == missing || y[i] == missing)
- points[i].back()->setMissing(true);
- }
- }
- else {
- bool scaled=(scaling==1 && offset == 0)?false:true;
- oriUnits=getString("units",false);
- if(oriUnits.find("/") == string::npos)
- {
- oriUnits=oriUnits + "/" + oriUnits;
- }
- points.setUnits(oriUnits);
- points.setScaledUnits("/");
-
-
- openFirstComponent();
- grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, x, distances, indexes);
- openSecondComponent();
- grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, y, distances, indexes);
- for (int i =0; i < nb; i++)
- {
- points[i].push_back(wind_mode_->values(outlons[i],outlats[i],x[i],y[i], distances[i]));
- if(x[i] == missing || y[i] == missing)
- points[i].back()->setMissing(true);
- }
- }
+ int nb = points.size();
+ double inlats[nb];
+ double inlons[nb];
+ double outlats[nb];
+ double outlons[nb];
+ double values[nb];
+ double x[nb];
+ double y[nb];
+ double distances[nb];
+
+ double scaling, offset;
+ string oriUnits, derivedUnits;
+ string representation = getString("typeOfGrid");
+ //Scaling works only for scalar data!!!
+
+ try
+ {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->scaling(*this, scaling, offset,oriUnits,derivedUnits);
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ scaling =1 ; offset =0;
+ }
+
+ for (int i =0; i < nb; i++)
+ {
+
+ inlats[i] = points[i].y();
+ inlons[i] = std::fmod(points[i].x(),360.);
+ if(inlons[i] < 0.) inlons[i]+=360.;
+ i++;
+ }
+
+ double missing = getDouble("missingValue");
+
+ if ( Data::dimension_ == 1 ) {
+ bool scaled=(scaling==1 && offset == 0)?false:true;
+ points.setScaled(scaled);
+ points.setUnits(oriUnits);
+ points.setScaledUnits(derivedUnits);
+
+ field_ = open(field_);
+
+ nearestGridpoints(inlats, inlons, outlats, outlons, values, distances, nb, representation);
+
+ for (int i=0; i < nb; i++)
+ {
+ points[i].push_back(new ValuesCollectorData(outlons[i],outlats[i],values[i],distances[i]));
+ if(scaled)
+ points[i].back()->setScaledValue(scaling*values[i] + offset);
+ if(values[i] == missing)
+ points[i].back()->setMissing(true);
+ }
+ }
+ else { //if ( Data::dimension_ == 2 ) {
+
+ oriUnits=getString("units",false);
+ if(oriUnits.find("/") == string::npos)
+ {
+ oriUnits=oriUnits + "/" + oriUnits;
+ }
+ points.setUnits(oriUnits);
+ points.setScaledUnits("/");
+
+
+ openFirstComponent();
+ nearestGridpoints(inlats, inlons, outlats, outlons, x, distances, nb, representation);
+ openSecondComponent();
+ nearestGridpoints(inlats, inlons, outlats, outlons, y, distances, nb, representation);
+ for (int i =0; i < nb; i++)
+ {
+ points[i].push_back(wind_mode_->values(outlons[i],outlats[i],x[i],y[i], distances[i]));
+ if(x[i] == missing || y[i] == missing)
+ points[i].back()->setMissing(true);
+ }
+ }
}
void GribDecoder::visit(MagnifierCollector& magnifier)
{
- const Transformation& transformation = magnifier.transformation();
- PointsHandler& points = this->points(transformation);
- points.setToFirst();
+ const Transformation& transformation = magnifier.transformation();
+ PointsHandler& points = this->points(transformation);
+ points.setToFirst();
- while ( points.more() )
- {
- magnifier.push_back(transformation(points.current()));
- points.advance();
- }
+ while ( points.more() )
+ {
+ magnifier.push_back(transformation(points.current()));
+ points.advance();
+ }
}
const DateDescription& GribDecoder::timeStamp()
{
- vector<string> need;
- need.push_back("<grib_info key='valid-date' format='%Y-%m-%d %H:%M:00'/>");
- need.push_back("<grib_info key='level'/>");
- need.push_back("<grib_info key='typeOfLevel'/>");
+ vector<string> need;
+ need.push_back("<grib_info key='valid-date' format='%Y-%m-%d %H:%M:00'/>");
+ need.push_back("<grib_info key='level'/>");
+ need.push_back("<grib_info key='typeOfLevel'/>");
- TagHandler helper;
- GribTag tag1(*this, helper);
- for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
- tag1.decode(*t);
+ TagHandler helper;
+ GribTag tag1(*this, helper);
+ for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
+ tag1.decode(*t);
- timeStamp_ = DateDescription(helper.get("grib", "valid-date"), index_, internalIndex_);
- dataLevel_ = LevelDescription::level(helper.get("grib", "typeOfLevel"), tonumber(helper.get("grib", "level")), index_, internalIndex_);
+ timeStamp_ = DateDescription(helper.get("grib", "valid-date"), index_, internalIndex_);
+ dataLevel_ = LevelDescription::level(helper.get("grib", "typeOfLevel"), tonumber(helper.get("grib", "level")), index_, internalIndex_);
- return timeStamp_;
+ return timeStamp_;
}
const LevelDescription& GribDecoder::level()
{
- timeStamp();
- return dataLevel_;
+ timeStamp();
+ return dataLevel_;
}
-void GribDecoder::visit(MetaDataCollector& step)
+void GribDecoder::visit(MetaDataVisitor& meta)
{
- // Here we gather information for the label!
- const Transformation& transformation = step.transformation();
+ vector<string> need;
- field_ = open(field_); // just to be sure the file is opened!
+ need.push_back("<grib_info key='shortName'/>");
+ need.push_back("<grib_info key='name'/>");
+ need.push_back("<grib_info key='level'/>");
+ need.push_back("<grib_info key='base-date' format='%Y-%m-%d %H:%M:00'/>");
+ need.push_back("<grib_info key='valid-date' format='%Y-%m-%d %H:%M:00'/>");
- initInfo();
- //Collect infos
- if(step.empty())
- {
- MetviewIcon::visit(step);
- return;
- }
+ TagHandler helper;
+ GribTag tag1(*this, helper);
+ for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
+ {
+ tag1.decode(*t);
+ }
- try {
- bool members=false;
- vector<string> need;
- if(name_.empty())
- {
- members=true;
- need.push_back("<grib_info key='shortName'/>");
- need.push_back("<grib_info key='level'/>");
- need.push_back("<grib_info key='start-date' format='%Y-%m-%d %H:%M:00'/>");
- need.push_back("<grib_info key='end-date' format='%Y-%m-%d %H:%M:00'/>");
- }
-
- for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
- {
- //If key is not found in information we use gribapi
- if(information_.find(key->first) == information_.end())
- {
- //Compute stats
- if (step.attribute(key->first).group() == MetaDataAttribute::StatsGroup)
- {
- stats_.clear();
-
-
- PointsHandler& points = this->points(transformation, false);
-
- points.setToFirst();
-
- while( points.more() )
- {
- stats_["value"].push_back(points.current().value());
- points.advance();
- }
-
- computeStats();
-
-
- }
- //We use gribapi
- else if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
- step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
- {
- if(step.attribute(key->first).type() != MetaDataAttribute::NumberType)
- {
- need.push_back("<grib_info key='"+key->first+ "'/>");
- }
- else
- {
- need.push_back("<grib_info key='"+key->first+ "' readAsLong='yes'/>");
- }
-
- }
- else if(key->first == "scaling_formula" ||key->first == "scaled_units" )
- {
- double scaling, offset;
- string oriUnits, derivedUnits;
- string representation = getString("typeOfGrid");
- try
- {
- auto_ptr<GribInterpretor> interpretor_(SimpleObjectMaker<GribInterpretor>::create(representation));
- interpretor_->scaling(*this, scaling, offset,oriUnits,derivedUnits);
- if(scaling==1 && offset == 0)
- {
- information_["scaling_formula"]="";
- information_["scaled_units"]="";
- }
- else
- {
- string offsetSign=(offset >=0)?"+":"-";
- information_["scaling_formula"]="(value * " + tostring(scaling) + ") " + offsetSign + " " + tostring(fabs(offset));
- information_["scaled_units"]= derivedUnits;
- }
- }
- catch (NoFactoryException&)
- {
- MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
- information_[key->first]="N/A";
- }
-
- }
-
- }
- //If key is found in information_ we copy it
- else
- {
- key->second=information_[key->first];
- }
- }
-
-
- if(!need.empty())
- {
- TagHandler helper;
- GribTag tag1(*this, helper);
- for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
- {
- tag1.decode(*t);
- }
-
- if(members)
- {
- name_ = helper.get("grib", "shortName") + " " + helper.get("grib", "level");
-
- from_ = DateTime(helper.get("grib", "start-date"));
- to_ = DateTime(helper.get("grib", "end-date"));
- }
-
- for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
- {
- if(information_.find(key->first) == information_.end())
- {
- if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
- step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
- {
- key->second = helper.get("grib", key->first);
- setInfo(key->first,key->second);
- }
- }
-
- }
-
- }
- }
-
- catch (...) {}
+ ostringstream grib;
+ grib << "{\"level\":\""<< helper.get("grib", "level") << "\",";
+ grib << "\"name\":\""<< helper.get("grib", "name") << "\",";
+ grib << "\"base-date\":\""<< helper.get("grib", "base-date") << "\",";
+ grib << "\"valid-date\":\""<< helper.get("grib", "valid-date") << "\"}";
+ meta.add("grib", grib.str());
}
-MatrixHandler& GribDecoder::direction() {
-
- decode2D();
- // Now X et X components are ready ..
- // We compute the direction in matrix_ and send it back.
-
- matrix_ = xComponent_;
-
- vector<double>::const_iterator x = xComponent_->begin();
- vector<double>::const_iterator y = yComponent_->begin();
- vector<double> directions;
- // MagLog::dev()<< "missing1-->" << in1->missing() << endl;
- // MagLog::dev()<< "missing2-->" << in2->missing() << endl;
- while ( x != xComponent_->end() && x != yComponent_->end() ) {
- if ( *x == xComponent_->missing() || *y == yComponent_->missing() )
- directions.push_back(xComponent_->missing());
- else
- directions.push_back(atan2((*y), (*x)) );
- ++x;
- ++y;
- }
- matrix_->clear();
- xComponent_ = 0;
+void GribDecoder::visit(MetaDataCollector& step)
+{
+ // Here we gather information for the label!
+ const Transformation& transformation = step.transformation();
+
+ field_ = open(field_); // just to be sure the file is opened!
+
+ initInfo();
+
+ //Collect infos
+ if(step.empty())
+ {
+ MetviewIcon::visit(step);
+ return;
+ }
+
+ try {
+ bool members=false;
+ vector<string> need;
+ if(name_.empty())
+ {
+ members=true;
+ need.push_back("<grib_info key='shortName'/>");
+ need.push_back("<grib_info key='level'/>");
+ need.push_back("<grib_info key='start-date' format='%Y-%m-%d %H:%M:00'/>");
+ need.push_back("<grib_info key='end-date' format='%Y-%m-%d %H:%M:00'/>");
+ }
+ for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
+ {
+ //If key is not found in information we use gribapi
+ if(information_.find(key->first) == information_.end())
+ {
+ //Compute stats
+ if (step.attribute(key->first).group() == MetaDataAttribute::StatsGroup)
+ {
+ stats_.clear();
+
+
+ PointsHandler& points = this->points(transformation, false);
+
+ points.setToFirst();
+
+ while( points.more() )
+ {
+ stats_["value"].push_back(points.current().value());
+ points.advance();
+ }
+
+ computeStats();
+
+
+ }
+ //We use gribapi
+ else if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
+ step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
+ {
+ if(step.attribute(key->first).type() != MetaDataAttribute::NumberType)
+ {
+ need.push_back("<grib_info key='"+key->first+ "'/>");
+ }
+ else
+ {
+ need.push_back("<grib_info key='"+key->first+ "' readAsLong='yes'/>");
+ }
+
+ }
+ else if(key->first == "scaling_formula" ||key->first == "scaled_units" )
+ {
+ double scaling, offset;
+ string oriUnits, derivedUnits;
+ string representation = getString("typeOfGrid");
+ try
+ {
+ auto_ptr<GribInterpretor> interpretor_(SimpleObjectMaker<GribInterpretor>::create(representation));
+ interpretor_->scaling(*this, scaling, offset,oriUnits,derivedUnits);
+ if(scaling==1 && offset == 0)
+ {
+ information_["scaling_formula"]="";
+ information_["scaled_units"]="";
+ }
+ else
+ {
+ string offsetSign=(offset >=0)?"+":"-";
+ information_["scaling_formula"]="(value * " + tostring(scaling) + ") " + offsetSign + " " + tostring(fabs(offset));
+ information_["scaled_units"]= derivedUnits;
+ }
+ }
+ catch (NoFactoryException&)
+ {
+ MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<< std::endl;;
+ information_[key->first]="N/A";
+ }
+
+ }
+
+ }
+ //If key is found in information_ we copy it
+ else
+ {
+ key->second=information_[key->first];
+ }
+ }
- for (vector<double>::iterator d = directions.begin(); d != directions.end(); ++d) {
- matrix_->push_back(*d);
- }
- matrixHandlers_.push_back(new MatrixHandler(*matrix_));
- return *(matrixHandlers_.back());
+ if(!need.empty())
+ {
+ TagHandler helper;
+ GribTag tag1(*this, helper);
+ for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
+ {
+ tag1.decode(*t);
+ }
+
+ if(members)
+ {
+ name_ = helper.get("grib", "shortName") + " " + helper.get("grib", "level");
+
+ from_ = DateTime(helper.get("grib", "start-date"));
+ to_ = DateTime(helper.get("grib", "end-date"));
+ }
+
+ for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
+ {
+ if(information_.find(key->first) == information_.end())
+ {
+ if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
+ step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
+ {
+ key->second = helper.get("grib", key->first);
+ setInfo(key->first,key->second);
+ }
+ }
+
+ }
-}
-void GribDecoder::decode(const Transformation& transformation)
-{
- if (matrix_) return;
+ }
+ }
- field_ = open(field_);
+ catch (...) {}
- read(&matrix_, transformation);
- if (!matrix_) return;
+}
+MatrixHandler& GribDecoder::direction() {
- // here we build information for the layers!
- TagHandler helper;
- vector<string> need;
- need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='start-date' format='%Y-%m-%d %H:%M:00'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
- GribTag tag1(*this, helper);
+ decode2D();
+ // Now X et X components are ready ..
+ // We compute the direction in matrix_ and send it back.
- for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
- {
- tag1.decode(*t);
- }
+ matrix_ = xComponent_;
- name_ = helper.get("grib"+id_, "shortName") + "-" + helper.get("grib"+id_, "level");
- name_ = iconName_;
- layerId_ = name_ + file_name_;
- from_ = DateTime(helper.get("grib"+id_, "start-date"));
- to_ = DateTime(helper.get("grib"+id_, "end-date"));
-}
+ vector<double>::const_iterator x = xComponent_->begin();
+ vector<double>::const_iterator y = yComponent_->begin();
+ vector<double> directions;
+ // MagLog::dev()<< "missing1-->" << in1->missing() << endl;
+ // MagLog::dev()<< "missing2-->" << in2->missing() << endl;
+ while ( x != xComponent_->end() && x != yComponent_->end() ) {
+ if ( *x == xComponent_->missing() || *y == yComponent_->missing() )
+ directions.push_back(xComponent_->missing());
+ else
+ directions.push_back(atan2((*x), (*y)) );
+ ++x;
+ ++y;
+ }
+ matrix_->clear();
+ xComponent_ = 0;
-void GribDecoder::decode()
-{
- if ( dimension_ == 1) {
- if (matrix_) return;
- field_ = open(field_);
- read(&matrix_);
- if (!matrix_) return;
- }
- else {
- decode2D();
- }
+ for (vector<double>::iterator d = directions.begin(); d != directions.end(); ++d) {
+ matrix_->push_back(*d);
+ }
- // here we build information for the layers!
- TagHandler helper;
- vector<string> need;
- need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='start-date' format='%Y-%m-%d %H:%M:00'/>");
- need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
- GribTag tag1(*this, helper);
+ matrixHandlers_.push_back(new MatrixHandler(*matrix_));
+ return *(matrixHandlers_.back());
- for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
- {
- tag1.decode(*t);
- }
+}
+void GribDecoder::decode(const Transformation& transformation)
+{
+ if (matrix_) return;
+
+ field_ = open(field_);
+
+ read(&matrix_, transformation);
+ if (!matrix_) return;
+
+ // here we build information for the layers!
+ TagHandler helper;
+ vector<string> need;
+ need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='start-date' format='%Y-%m-%d %H:%M:00'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
+ GribTag tag1(*this, helper);
+
+ for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
+ {
+ tag1.decode(*t);
+ }
+
+ name_ = helper.get("grib"+id_, "shortName") + "-" + helper.get("grib"+id_, "level");
+ name_ = iconName_;
+ layerId_ = name_ + file_name_;
+ from_ = DateTime(helper.get("grib"+id_, "start-date"));
+ to_ = DateTime(helper.get("grib"+id_, "end-date"));
+}
- name_ = helper.get("grib"+id_, "shortName") + "-" + helper.get("grib"+id_, "level");
- name_ = iconName_;
- layerId_ = name_ + file_name_;
- from_ = DateTime(helper.get("grib"+id_, "start-date"));
- to_ = DateTime(helper.get("grib"+id_, "end-date"));
+void GribDecoder::decode()
+{
+
+ if ( dimension_ == 1) {
+ if (matrix_) return;
+ field_ = open(field_);
+ read(&matrix_);
+ if (!matrix_) return;
+ }
+ else {
+ decode2D();
+ }
+
+
+ // here we build information for the layers!
+ TagHandler helper;
+ vector<string> need;
+ need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='start-date' format='%Y-%m-%d %H:%M:00'/>");
+ need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
+ GribTag tag1(*this, helper);
+
+ for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
+ {
+ tag1.decode(*t);
+ }
+
+ name_ = helper.get("grib"+id_, "shortName") + "-" + helper.get("grib"+id_, "level");
+ name_ = iconName_;
+ layerId_ = name_ + file_name_;
+ from_ = DateTime(helper.get("grib"+id_, "start-date"));
+ to_ = DateTime(helper.get("grib"+id_, "end-date"));
}
-void GribDecoder::visit(TextVisitor& title)
+void GribDecoder::visit(TextVisitor& title)
{
- try {
- field_ = open(field_);
- }
- catch ( ... )
- {
- return;
- }
+ try {
+ field_ = open(field_);
+ }
+ catch ( ... )
+ {
+ return;
+ }
- vector<string> titles;
+ vector<string> titles;
- title.titles(titles);
- GribTag tag(*this, title);
+ title.titles(titles);
+ GribTag tag(*this, title);
- for ( vector<string>::const_iterator t = titles.begin(); t != titles.end(); ++t ) {
- tag.decode(*t);
- }
+ for ( vector<string>::const_iterator t = titles.begin(); t != titles.end(); ++t ) {
+ tag.decode(*t);
+ }
}
-void GribDecoder::decodeRaster(const Transformation& transformation)
+void GribDecoder::decodeRaster(const Transformation& transformation)
{
- field_ = open(field_);
-
- string representation = getString("typeOfGrid");
+ field_ = open(field_);
- try {
- if ( !interpretor_ ) {
- interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
- }
- interpretor_->interpretAsRaster(*this, raster_, transformation);
- }
+ string representation = getString("typeOfGrid");
- catch (NoFactoryException&)
- {
- MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n";
- throw MagicsException("Grib Decoder: Representation [] not yet supported.");
- }
+ try {
+ if ( !interpretor_ ) {
+ interpretor_ = SimpleObjectMaker<GribInterpretor>::create(representation);
+ }
+ interpretor_->interpretAsRaster(*this, raster_, transformation);
+ }
+
+ catch (NoFactoryException&)
+ {
+ MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n";
+ throw MagicsException("Grib Decoder: Representation [] not yet supported.");
+ }
}
void GribDecoder::initInfo()
{
- if(information_.find("_datatype") == information_.end())
- {
- setInfo("_datatype","GRIB");
-
- char buf[1024];
- int count = readlink(file_name_.c_str(), buf, sizeof(buf));
- if (count > 0)
- {
- buf[count] = '\0';
- setInfo("path", string(buf));
- }
- else
- {
- setInfo("path", file_name_);
- }
- setInfo("MV_Format","GRIB");
- }
+ if(information_.find("_datatype") == information_.end())
+ {
+ setInfo("_datatype","GRIB");
+
+ char buf[1024];
+ int count = readlink(file_name_.c_str(), buf, sizeof(buf));
+ if (count > 0)
+ {
+ buf[count] = '\0';
+ setInfo("path", string(buf));
+ }
+ else
+ {
+ setInfo("path", file_name_);
+ }
+ setInfo("MV_Format","GRIB");
+ }
}
@@ -1864,180 +1909,180 @@ namespace magics {
class GribInfo
{
public:
- GribInfo() {}
- virtual ~GribInfo() {}
- virtual void operator()(ostream&, const GribDecoder&) = 0;
+ GribInfo() {}
+ virtual ~GribInfo() {}
+ virtual void operator()(ostream&, const GribDecoder&) = 0;
};
class GribParameter : public GribInfo
{
-public:
- GribParameter() {}
- ~GribParameter() {}
- void operator()(ostream& out, const GribDecoder& grib)
- {
- string val = grib.getString("name");
- out << val;
- }
+public:
+ GribParameter() {}
+ ~GribParameter() {}
+ void operator()(ostream& out, const GribDecoder& grib)
+ {
+ string val = grib.getString("name");
+ out << val;
+ }
};
class GribParamCriter : public MatchCriteria
{
public:
- GribParamCriter() {}
- ~GribParamCriter() {}
- bool verify(const GribDecoder& grib, const string&, const string& val)
- {
- long param = grib.getLong("paramId");
- return (tostring(param) == val);
- }
+ GribParamCriter() {}
+ ~GribParamCriter() {}
+ bool verify(const GribDecoder& grib, const string&, const string& val)
+ {
+ long param = grib.getLong("paramId");
+ return (tostring(param) == val);
+ }
};
class GribLocalCriter : public MatchCriteria
{
public:
- GribLocalCriter() {}
- ~GribLocalCriter() {}
- bool verify(const GribDecoder& grib, const string& param, const string& val)
- {
- string key = param;
- string criter = grib.getString(key, false); // 'false' to avoid warnings if key is absent
- MagLog::debug() << "I am verifing " << param << " for a GribDecoder : " << criter << " == " << val << "???" << "\n";
- return (criter == val);
- }
+ GribLocalCriter() {}
+ ~GribLocalCriter() {}
+ bool verify(const GribDecoder& grib, const string& param, const string& val)
+ {
+ string key = param;
+ string criter = grib.getString(key, false); // 'false' to avoid warnings if key is absent
+ MagLog::debug() << "I am verifing " << param << " for a GribDecoder : " << criter << " == " << val << "???" << "\n";
+ return (criter == val);
+ }
};
class GribObsDiagCriter : public MatchCriteria
{
public:
- GribObsDiagCriter() {}
- ~GribObsDiagCriter() {}
- bool verify(const GribDecoder& grib, const string&, const string& )
- {
- string param = grib.getString("observationDiagnostic", false); // do not warn if the key is absent
- return (param != "");
- }
+ GribObsDiagCriter() {}
+ ~GribObsDiagCriter() {}
+ bool verify(const GribDecoder& grib, const string&, const string& )
+ {
+ string param = grib.getString("observationDiagnostic", false); // do not warn if the key is absent
+ return (param != "");
+ }
};
class GribLocalDefHandler : public TitleFieldHandler
{
public:
- GribLocalDefHandler() {}
- ~GribLocalDefHandler() {}
+ GribLocalDefHandler() {}
+ ~GribLocalDefHandler() {}
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
- ostringstream out;
- string local = grib.getString("localDefinitionNumber");
- out << "local definition =" << local << " ";
- title.back() += out.str();
- }
+ ostringstream out;
+ string local = grib.getString("localDefinitionNumber");
+ out << "local definition =" << local << " ";
+ title.back() += out.str();
+ }
};
class GribObsDiagHandler : public TitleFieldHandler
{
public:
- GribObsDiagHandler() {}
- ~GribObsDiagHandler() {}
+ GribObsDiagHandler() {}
+ ~GribObsDiagHandler() {}
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
- ostringstream out;
- string local = grib.getString("observationDiagnostic");
- out << "diagnostic =" << local << " ";
- title.back() += out.str();
- }
+ ostringstream out;
+ string local = grib.getString("observationDiagnostic");
+ out << "diagnostic =" << local << " ";
+ title.back() += out.str();
+ }
};
class GribObstatHandler : public TitleFieldHandler
{
public:
- GribObstatHandler() {}
- ~GribObstatHandler() {}
+ GribObstatHandler() {}
+ ~GribObstatHandler() {}
- void operator()(TitleField&, vector<string>& /*title*/, const GribDecoder& grib)
- {
+ void operator()(TitleField&, vector<string>& /*title*/, const GribDecoder& grib)
+ {
- }
+ }
};
class GribLocalHandler : public TitleFieldHandler
{
public:
- GribLocalHandler(const string& local) : local_(local) {}
- ~GribLocalHandler() {}
+ GribLocalHandler(const string& local) : local_(local) {}
+ ~GribLocalHandler() {}
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
- ostringstream out;
- string code = grib.getString(local_);
- out << local_ << "=" << code << " ";
- title.back()+= out.str();
- }
+ ostringstream out;
+ string code = grib.getString(local_);
+ out << local_ << "=" << code << " ";
+ title.back()+= out.str();
+ }
protected :
- string local_;
+ string local_;
};
-class GribStreamHandler : public GribLocalHandler
+class GribStreamHandler : public GribLocalHandler
{
public:
- GribStreamHandler() : GribLocalHandler("marsStream") {}
- ~GribStreamHandler() {}
+ GribStreamHandler() : GribLocalHandler("marsStream") {}
+ ~GribStreamHandler() {}
};
-class GribClassHandler : public GribLocalHandler
+class GribClassHandler : public GribLocalHandler
{
public:
- GribClassHandler() : GribLocalHandler("marsClass") {}
- ~GribClassHandler() {}
+ GribClassHandler() : GribLocalHandler("marsClass") {}
+ ~GribClassHandler() {}
};
-class GribTypeHandler : public GribLocalHandler
+class GribTypeHandler : public GribLocalHandler
{
public:
- GribTypeHandler() : GribLocalHandler("marsType") {}
- ~GribTypeHandler() {}
+ GribTypeHandler() : GribLocalHandler("marsType") {}
+ ~GribTypeHandler() {}
};
class GribParamHandler : public TitleFieldHandler
{
public:
- GribParamHandler() {}
- ~GribParamHandler() {}
- virtual void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
-
- string param = grib.getString("name");
- title.back()+=param;
- }
+ GribParamHandler() {}
+ ~GribParamHandler() {}
+ virtual void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
+
+ string param = grib.getString("name");
+ title.back()+=param;
+ }
};
class GribKeyHandler : public TitleFieldHandler
{
public:
- GribKeyHandler() {}
- ~GribKeyHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
+ GribKeyHandler() {}
+ ~GribKeyHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
- char x[256];
+ char x[256];
- string key = field.attribute("key", "");
- string value = grib.getString(key);
- string format = field.attribute("format", "%s");
- sprintf(x, format.c_str(), value.c_str());
+ string key = field.attribute("key", "");
+ string value = grib.getString(key);
+ string format = field.attribute("format", "%s");
+ sprintf(x, format.c_str(), value.c_str());
- title.back() += string(x);
+ title.back() += string(x);
- }
+ }
};
@@ -2045,160 +2090,160 @@ public:
class GribBaseDateHandler : public TitleFieldHandler
{
public:
- GribBaseDateHandler() {}
- ~GribBaseDateHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
-
- ostringstream out;
-
- long date = grib.getLong("date");
- long hour = grib.getLong("hour");
- long mn = grib.getLong("minute");
- MagDate part1 = MagDate(date);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
- const long type = grib.getLong("significanceOfReferenceTime", false);
+ GribBaseDateHandler() {}
+ ~GribBaseDateHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
+
+ ostringstream out;
+
+ long date = grib.getLong("date");
+ long hour = grib.getLong("hour");
+ long mn = grib.getLong("minute");
+ MagDate part1 = MagDate(date);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+ const long type = grib.getLong("significanceOfReferenceTime", false);
if ( type == 2 ) { // Verifying time of forecast
- long step = grib.getLong("step"); // needs steps in second! // default is in hours. Set 'stepUnits' to change.
- full = full + (step*-3600);
+ long step = grib.getLong("step"); // needs steps in second! // default is in hours. Set 'stepUnits' to change.
+ full = full + (step*-3600);
}
- string format = field.attribute("format", "%A %d %B %Y at %H%M UTC");
+ string format = field.attribute("format", "%A %d %B %Y at %H%M UTC");
- title.back() += full.tostring(format);
- }
+ title.back() += full.tostring(format);
+ }
};
class GribValidDateHandler : public TitleFieldHandler
{
public:
- GribValidDateHandler() {}
- ~GribValidDateHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
+ GribValidDateHandler() {}
+ ~GribValidDateHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
- ostringstream out;
- long date = grib.getLong("date");
- long hour = grib.getLong("hour");
- long mn = grib.getLong("minute");
+ ostringstream out;
+ long date = grib.getLong("date");
+ long hour = grib.getLong("hour");
+ long mn = grib.getLong("minute");
- long step = computeStep(grib, "step");
+ long step = computeStep(grib, "step");
- MagDate part1 = MagDate(date);
- MagTime part2 = MagTime(hour, mn, 0);
- DateTime full(part1, part2);
- const long type = grib.getLong("significanceOfReferenceTime", false);
+ MagDate part1 = MagDate(date);
+ MagTime part2 = MagTime(hour, mn, 0);
+ DateTime full(part1, part2);
+ const long type = grib.getLong("significanceOfReferenceTime", false);
if ( type != 2 ) { // Verifying time of forecast
- full = full + step;
+ full = full + step;
}
- string format = field.attribute("format", "%A %d %B %Y %H%M UTC");
+ string format = field.attribute("format", "%A %d %B %Y %H%M UTC");
- title.back() += full.tostring(format);
+ title.back() += full.tostring(format);
- }
+ }
};
class GribStepHandler : public TitleFieldHandler
{
public:
- GribStepHandler() {}
- ~GribStepHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
+ GribStepHandler() {}
+ ~GribStepHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
- ostringstream out;
- long istep = grib.getLong("startStep");
+ ostringstream out;
+ long istep = grib.getLong("startStep");
- ostringstream step;
- step << istep;
- string format = field.attribute("format", "t+%s");
- out << SimpleStringFormat(step.str(), format);
- title.back() += out.str();
- }
+ ostringstream step;
+ step << istep;
+ string format = field.attribute("format", "t+%s");
+ out << SimpleStringFormat(step.str(), format);
+ title.back() += out.str();
+ }
};
class GribLevelHandler : public TitleFieldHandler
{
public:
- GribLevelHandler() {
- if (map_.empty()) {
- map_["Surface"] = &GribLevelHandler::surface;
- map_["Unknown"] = &GribLevelHandler::surface;
- map_["isobaricInhPa"] = &GribLevelHandler::isobaricInhPa;
- map_["heightAboveGround"] = &GribLevelHandler::heightAboveGround;
- map_["heightAboveGround"] = &GribLevelHandler::heightAboveGround;
- map_["hybrid"] = &GribLevelHandler::hybrid;
- }
- }
-
- ~GribLevelHandler() {}
- typedef string (GribLevelHandler::*Builder)(const string& def, const GribDecoder& grib) const;
-
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
- ostringstream out;
-
- string level = grib.getString("typeOfLevel");
-
-
- map<string, GribLevelHandler::Builder>::iterator help = map_.find(level);
- if ( help != map_.end() ) out << (this->*help->second)(level, grib) << " ";
- else out << level << " ";
-
- title.back() += out.str();
-
- }
-
-protected:
- static map<string, GribLevelHandler::Builder> map_;
-
- string surface(const string&, const GribDecoder& ) const
- {
- return "";
- }
- string unknown(const string& level, const GribDecoder& ) const
- {
- ostringstream out;
- out << "Unknown type of level[" << level << "]";
- return out.str();
- }
- string isobaricInhPa(const string& , const GribDecoder& grib) const
- {
- ostringstream out;
- long level = grib.getLong("level");
- out << level << " " << "hPa";
- return out.str();
- }
- string pv(const string& , const GribDecoder& grib) const
- {
- ostringstream out;
- long level = grib.getLong("level");
- out << level << " mPVU";
- return out.str();
- }
- string heightAboveGround(const string& , const GribDecoder& grib) const
- {
- ostringstream out;
- long level = grib.getLong("level");
- out << level << " m";
- return out.str();
- }
- string hybrid(const string& , const GribDecoder& grib) const
- {
- ostringstream out;
- long level = grib.getLong("level");
- out << "Model level " << level;
- return out.str();
- }
+ GribLevelHandler() {
+ if (map_.empty()) {
+ map_["Surface"] = &GribLevelHandler::surface;
+ map_["Unknown"] = &GribLevelHandler::surface;
+ map_["isobaricInhPa"] = &GribLevelHandler::isobaricInhPa;
+ map_["heightAboveGround"] = &GribLevelHandler::heightAboveGround;
+ map_["heightAboveGround"] = &GribLevelHandler::heightAboveGround;
+ map_["hybrid"] = &GribLevelHandler::hybrid;
+ }
+ }
+
+ ~GribLevelHandler() {}
+ typedef string (GribLevelHandler::*Builder)(const string& def, const GribDecoder& grib) const;
+
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
+ ostringstream out;
+
+ string level = grib.getString("typeOfLevel");
+
+
+ map<string, GribLevelHandler::Builder>::iterator help = map_.find(level);
+ if ( help != map_.end() ) out << (this->*help->second)(level, grib) << " ";
+ else out << level << " ";
+
+ title.back() += out.str();
+
+ }
+
+protected:
+ static map<string, GribLevelHandler::Builder> map_;
+
+ string surface(const string&, const GribDecoder& ) const
+ {
+ return "";
+ }
+ string unknown(const string& level, const GribDecoder& ) const
+ {
+ ostringstream out;
+ out << "Unknown type of level[" << level << "]";
+ return out.str();
+ }
+ string isobaricInhPa(const string& , const GribDecoder& grib) const
+ {
+ ostringstream out;
+ long level = grib.getLong("level");
+ out << level << " " << "hPa";
+ return out.str();
+ }
+ string pv(const string& , const GribDecoder& grib) const
+ {
+ ostringstream out;
+ long level = grib.getLong("level");
+ out << level << " mPVU";
+ return out.str();
+ }
+ string heightAboveGround(const string& , const GribDecoder& grib) const
+ {
+ ostringstream out;
+ long level = grib.getLong("level");
+ out << level << " m";
+ return out.str();
+ }
+ string hybrid(const string& , const GribDecoder& grib) const
+ {
+ ostringstream out;
+ long level = grib.getLong("level");
+ out << "Model level " << level;
+ return out.str();
+ }
};
map<string, GribLevelHandler::Builder> GribLevelHandler::map_;
@@ -2206,84 +2251,84 @@ map<string, GribLevelHandler::Builder> GribLevelHandler::map_;
class GribTimeHandler : public TitleFieldHandler
{
public:
- GribTimeHandler() {}
- ~GribTimeHandler() {}
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
- // if (!grib.getText()) return;
- // ostringstream out;
- // grib_int_t idate;
- // grib_get(grib.id(),(grib_string_t*)"time","I",&idate);
- //
- // out << "Time:" << idate;
- // title.add(out.str());
-
- title.back() += "Time? ";
- }
+ GribTimeHandler() {}
+ ~GribTimeHandler() {}
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
+ // if (!grib.getText()) return;
+ // ostringstream out;
+ // grib_int_t idate;
+ // grib_get(grib.id(),(grib_string_t*)"time","I",&idate);
+ //
+ // out << "Time:" << idate;
+ // title.add(out.str());
+
+ title.back() += "Time? ";
+ }
};
class GribCentreHandler : public TitleFieldHandler
{
public:
- GribCentreHandler() {}
- ~GribCentreHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
- string format = field.attribute("format", "%s");
- string style = field.attribute("style", "short");
- string centre = grib.getString("centre");
-
- title.back() += centre;
- }
+ GribCentreHandler() {}
+ ~GribCentreHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
+ string format = field.attribute("format", "%s");
+ string style = field.attribute("style", "short");
+ string centre = grib.getString("centre");
+
+ title.back() += centre;
+ }
};
class GribProductHandler : public TitleFieldHandler
{
public:
- GribProductHandler() {}
- ~GribProductHandler() {}
- void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
- {
+ GribProductHandler() {}
+ ~GribProductHandler() {}
+ void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
+ {
- long type = grib.getLong("type");
+ long type = grib.getLong("type");
- GeneralDef def = TypeTable::definition(type);
- title.back() += def.longTitle();
- }
+ GeneralDef def = TypeTable::definition(type);
+ title.back() += def.longTitle();
+ }
};
class GribPlotTypeHandler : public TitleFieldHandler
{
public:
- GribPlotTypeHandler() {}
- ~GribPlotTypeHandler() {}
- void operator()(TitleField&, vector<string>&,const GribDecoder&)
- {
- //MagLog::warning() << "Plot Type: not implemented--> wait for the specification." << "\n";
- }
+ GribPlotTypeHandler() {}
+ ~GribPlotTypeHandler() {}
+ void operator()(TitleField&, vector<string>&,const GribDecoder&)
+ {
+ //MagLog::warning() << "Plot Type: not implemented--> wait for the specification." << "\n";
+ }
};
class NewLineHandler : public TitleFieldHandler
{
public:
- NewLineHandler() {}
- ~NewLineHandler() {}
- void operator()(TitleField&, vector<string>& title,const GribDecoder&)
- {
- title.push_back("");
- }
+ NewLineHandler() {}
+ ~NewLineHandler() {}
+ void operator()(TitleField&, vector<string>& title,const GribDecoder&)
+ {
+ title.push_back("");
+ }
};
class SatelliteHandler : public TitleFieldHandler
{
public:
- SatelliteHandler() {}
- ~SatelliteHandler() {}
- void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
- {
+ SatelliteHandler() {}
+ ~SatelliteHandler() {}
+ void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
+ {
static map<long, string> names;
if ( names.empty() ){
names[54] = "METEOSAT-7";
@@ -2293,24 +2338,24 @@ public:
names[259] = "GOES-15";
}
- long ident = grib.getLong("ident");
+ long ident = grib.getLong("ident");
map<long, string>::iterator sat = names.find(ident);
- if ( sat != names.end() )
+ if ( sat != names.end() )
title.back() += sat->second;
- else
+ else
title.back() += "satellite identifier " + tostring(ident);
- }
+ }
};
class ChannelHandler : public TitleFieldHandler
{
public:
- ChannelHandler() {}
- ~ChannelHandler() {}
- void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
- {
+ ChannelHandler() {}
+ ~ChannelHandler() {}
+ void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
+ {
map<long, map<long, string> > channels;
if ( channels.empty() ) {
map<long, string> l54;
@@ -2343,9 +2388,9 @@ public:
l259[4] = "IR 10-7";
channels[259] = l259;
}
- ostringstream out;
- long ident = grib.getLong("ident");
- long band = grib.getLong("channel");
+ ostringstream out;
+ long ident = grib.getLong("ident");
+ long band = grib.getLong("channel");
map<long, map<long, string> >::iterator sat = channels.find(ident);
@@ -2359,67 +2404,67 @@ public:
return;
}
- title.back() += channel->second;
- }
+ title.back() += channel->second;
+ }
};
class GribExpverHandler : public TitleFieldHandler
{
public:
- GribExpverHandler() {}
- ~GribExpverHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
-
- if ( !grib.getExpver() ) return;
- ostringstream out;
- string expver = grib.getString("mars.experimentVersionNumber");
- string format = field.attribute("format", "Expver=%s");
- out << SimpleStringFormat(expver, format);
- title.back() += out.str();
- }
+ GribExpverHandler() {}
+ ~GribExpverHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
+
+ if ( !grib.getExpver() ) return;
+ ostringstream out;
+ string expver = grib.getString("mars.experimentVersionNumber");
+ string format = field.attribute("format", "Expver=%s");
+ out << SimpleStringFormat(expver, format);
+ title.back() += out.str();
+ }
};
class GribEpsNumberInfoHandler : public TitleFieldHandler
{
public:
- GribEpsNumberInfoHandler() {}
- ~GribEpsNumberInfoHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
-
- // if (!grib.getText()) return;
- // ostringstream out;
- // grib_int_t local;
- // grib_get(grib.id(),(grib_string_t*)"localDefinition","I","localDefinitionNumber",&local);
- // if (local != 1) return;
- //
- // char number[1024];
- // grib_get(grib.id(),(grib_string_t*)"localDefinition","s","total",number);
- // string format = field.attribute("format", "(%s members)");
- //
- // out << SimpleStringFormat(number, format);
- // title.add(out.str());
-
- title.back() += "epsnumber?";
-
- }
+ GribEpsNumberInfoHandler() {}
+ ~GribEpsNumberInfoHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
+
+ // if (!grib.getText()) return;
+ // ostringstream out;
+ // grib_int_t local;
+ // grib_get(grib.id(),(grib_string_t*)"localDefinition","I","localDefinitionNumber",&local);
+ // if (local != 1) return;
+ //
+ // char number[1024];
+ // grib_get(grib.id(),(grib_string_t*)"localDefinition","s","total",number);
+ // string format = field.attribute("format", "(%s members)");
+ //
+ // out << SimpleStringFormat(number, format);
+ // title.add(out.str());
+
+ title.back() += "epsnumber?";
+
+ }
};
class GribUnitHandler : public TitleFieldHandler
{
public:
- GribUnitHandler() {}
- ~GribUnitHandler() {}
- void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
- {
- /*
- if (!grib.getText()) return;
- if ( !grib.getUnits() ) return;
- ostringstream out;
+ GribUnitHandler() {}
+ ~GribUnitHandler() {}
+ void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
+ {
+ /*
+ if (!grib.getText()) return;
+ if ( !grib.getUnits() ) return;
+ ostringstream out;
double id = grib.getDouble("paramId");
long centre = grib.getLong("centre");
@@ -2430,16 +2475,49 @@ public:
const ParamDef& parameter = LocalTable::localInfo(param, table, centre);
- string format = field.attribute("format", "Units:%s");
+ string format = field.attribute("format", "Units:%s");
string unit = (grib.getScaling()) ? parameter.derivedUnit() : parameter.originalUnit();
out << SimpleStringFormat(unit, format);
title.back() += out.str();
- */
- }
+ */
+ }
};
+double GribDecoder::uComponent(int index)
+{
+ return xValues_[index];
+}
+double GribDecoder::vComponent(int index)
+{
+ return yValues_[index];
+}
+void GribDecoder::uComponent()
+{
+ if ( xValues_ )
+ return;
+ size_t nb;
+ string name;
+ grib_handle* handle = uHandle(name);
+
+ grib_get_size(handle, "values", &nb);
+ xValues_ = new double[nb];
+ grib_get_double_array(handle, "values", xValues_, &nb);
+}
+void GribDecoder::vComponent()
+{
+ if ( yValues_ )
+ return;
+
+ string name;
+ grib_handle* handle = vHandle(name);
+ size_t nb;
+ grib_get_size(handle, "values", &nb);
+
+ yValues_ = new double[nb];
+ grib_get_double_array(handle, "values", yValues_, &nb);
+}
}// end namespace magics
diff --git a/src/decoders/GribDecoder.h b/src/decoders/GribDecoder.h
index c5eaaa8..a78517d 100644
--- a/src/decoders/GribDecoder.h
+++ b/src/decoders/GribDecoder.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,11 +18,11 @@
/*! \file GribDecoder.h
\brief Definition of the Template class GribDecoder.
-
+
Magics Team - ECMWF 2004
-
+
Started: Tue 16-Mar-2004
-
+
Changes:
*/
@@ -61,28 +61,32 @@ class GribMagException : public MagicsException
public:
GribMagException( const string& why ):
MagicsException("Grib API error message: " + why){}
-};
+};
class GribFileMagException : public MagicsException
{
public:
GribFileMagException(const string& file, int index)
- {
+ {
ostringstream s;
s << "Grib decoding failed: field " << index << " in " << file << endl;
what_ = s.str();
}
-};
+};
class GribLoop;
-class GribDecoder:
- public Decoder,
+
+
+class GribDecoder:
+ public Decoder,
public Data,
public GribDecoderAttributes
{
public:
GribDecoder();
- virtual ~GribDecoder();
+ virtual ~GribDecoder();
+
+ enum InterpolateMethod { nearest, nearest_valid, interpolate };
// implements BaseSceneObject interface
virtual void set(const map<string, string>& params) { GribDecoderAttributes::set(params); }
@@ -99,46 +103,57 @@ public:
void newPoint(const Transformation&, double, double, double, double, double, vector<CustomisedPoint*>&, double);
bool verify(const string& where) const;
MatrixHandler& direction();
- // Data Interface : info for the layer managment!
+ // Data Interface : info for the layer managment!
string layerId() { decode(); return layerId_; }
string name() { decode(); return name_; }
const DateTime& from() { decode(); return from_; }
const DateTime& to() { decode(); return to_; }
-
+
string title() {
return title_;
}
- bool interpolate() const { return magCompare(interpolation_method_, "interpolate"); }
+ static void scale(const string&, double&, double&);
+
+ InterpolateMethod interpolateMethod() const {
+ if ( magCompare(interpolation_method_, "interpolate") )
+ return interpolate;
+ if ( magCompare(interpolation_method_, "nearest") )
+ return nearest;
+ if ( magCompare(interpolation_method_, "nearest_valid") )
+ return nearest_valid;
+ }
+ int missingFill() const { return missing_fill_count_; }
bool getExpver() const { return expver_; }
void version();
-
-
+
+
// implements Decoder
void visit(AnimationRules&);
void visit(MetaDataCollector&);
void visit(MagnifierCollector&);
void visit(ValuesCollector&);
void visit(Transformation&);
-
+ void visit(MetaDataVisitor&);
+
const DateDescription& timeStamp();
const LevelDescription& level() ;
// implements Decoder
void visit(TextVisitor&);
-
+
PointsHandler& points()
{
decodePoints();
pointsHandlers_.push_back(new PointsHandler(points_));
- return *(pointsHandlers_.back());
- }
+ return *(pointsHandlers_.back());
+ }
PointsHandler& points(const Transformation& transformation)
{
decodePoints();
pointsHandlers_.push_back(new BoxPointsHandler(points_, transformation, true));
- return *(pointsHandlers_.back());
- }
+ return *(pointsHandlers_.back());
+ }
PointsHandler& points(const Transformation& transformation, bool all) {
decodePoints();
pointsHandlers_.push_back(new BoxPointsHandler(points_, transformation, !all));
@@ -150,7 +165,7 @@ public:
decode();
matrixHandlers_.push_back(new MatrixHandler(*matrix_));
- return *(matrixHandlers_.back());
+ return *(matrixHandlers_.back());
}
MatrixHandler& matrix(const Transformation& transformation)
{
@@ -158,16 +173,16 @@ public:
decode(transformation);
matrixHandlers_.push_back(new MatrixHandler(*matrix_));
- return *(matrixHandlers_.back());
+ return *(matrixHandlers_.back());
}
-
+
void setPath(const string& path) { file_name_ = path; }
-
+
RasterData& raster(const Transformation& transformation)
{
decodeRaster(transformation);
- return raster_;
- }
+ return raster_;
+ }
void customisedPoints(const Transformation& t, const std::set<string>& n, CustomisedPointsList& out, bool all)
{
@@ -196,23 +211,32 @@ public:
void read(Matrix **matrix, const Transformation&);
bool id(const string&, const string&) const;
+ grib_nearest* nearest_point_handle(bool keep);
+ void nearestGridpoints(double *inlats, double *inlons, double *outlats, double *outlons, double *values, double *distances, int nb, string &representation);
grib_handle* uHandle(string&);
grib_handle* vHandle(string&);
grib_handle* cHandle(string&);
+ double uComponent(int);
+ double vComponent(int);
+ void uComponent();
+ void vComponent();
+
grib_handle* handle() const { return handle_; }
void initInfo();
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
-
+ virtual void print(ostream&) const;
+
void handle(grib_handle*);
mutable Matrix* matrix_;
+ mutable double* xValues_;
+ mutable double* yValues_;
mutable Matrix* xComponent_;
- mutable Matrix* yComponent_;
+ mutable Matrix* yComponent_;
mutable Matrix* colourComponent_;
mutable RasterData raster_;
mutable PointsList points_;
@@ -229,14 +253,15 @@ protected:
map<double, std::set<double> > positions_;
-
+
grib_handle* handle_;
+ grib_nearest* nearest_;
grib_handle* field_;
grib_handle* component1_;
grib_handle* component2_;
grib_handle* colour_;
-
+
string title_;
static int count_;
friend class GribInterpretor;
@@ -264,9 +289,9 @@ public:
Data::dimension_ = 1;
}
- GribEntryDecoder(grib_handle* handle1, grib_handle* handle2) {
+ GribEntryDecoder(grib_handle* handle1, grib_handle* handle2) {
handle_ = handle1;
- handle1_ = handle1;
+ handle1_ = handle1;
handle2_ = handle2;
handle3_ = 0;
@@ -283,17 +308,17 @@ public:
grib_handle* open(grib_handle*, bool sendMsg = true);
- void openFirstComponent() {
- assert(handle1_);
+ void openFirstComponent() {
+ ASSERT(handle1_);
handle_ = handle1_;
}
-
- void openSecondComponent() {
- assert(handle2_);
+
+ void openSecondComponent() {
+ ASSERT(handle2_);
handle_ = handle2_;
}
void openThirdComponent() {
- assert(handle3_);
+ ASSERT(handle3_);
handle_ = handle3_;
}
void readColourComponent() {
@@ -304,7 +329,7 @@ public:
else
colourComponent_ = 0;
}
-
+
protected:
grib_handle* handle1_;
grib_handle* handle2_;
@@ -316,36 +341,36 @@ class GribLoop : public GribLoopAttributes, public DataLoop
public:
GribLoop();
virtual ~GribLoop();
-
-
-
+
+
+
void set(const map<string, string>& map) { GribLoopAttributes::set(map); }
void set(const XmlNode& node) { GribLoopAttributes::set(node); }
-
-
+
+
Data* current();
bool hasMore();
void next();
void setToFirst();
-
-
-
+
+
+
protected:
- virtual void print(ostream&) const;
+ virtual void print(ostream&) const;
vector<GribDecoder*> gribs_;
GribDecoder* currentgrib_;
friend class GribDecoder;
vector<int>::iterator currentDim_;
- vector<int>::iterator currentPos_;
+ vector<long int>::iterator currentPos_;
+
-
FILE* file_;
static map<string, string> ids_;
static int index_;
int uniqueId_;
int counter_;
-
+
private:
//! Copy constructor - No copy allowed
GribLoop(const GribLoop&);
@@ -356,7 +381,7 @@ private:
//! Overloaded << operator to call print().
friend ostream& operator<<(ostream& s,const GribLoop& p)
{ p.print(s); return s; }
-
+
};
diff --git a/src/decoders/GribInterpretor.h b/src/decoders/GribInterpretor.h
index 28a29d2..1b09565 100644
--- a/src/decoders/GribInterpretor.h
+++ b/src/decoders/GribInterpretor.h
@@ -45,6 +45,18 @@ class Transformation;
class RasterData;
+struct Index
+ {
+ int index_;
+ double lat_;
+ double lon_;
+ bool used_;
+ Index(int index, double lat, double lon) : index_(index), lat_(lat), lon_(lon), used_(false) {}
+ void print()
+ {
+ cout << "[" << lat_ << ", " << lon_ << "]" << endl;
+ }
+ };
class GribInterpretor {
@@ -71,12 +83,31 @@ public:
void interpolate(const GribDecoder& grib, Matrix& matrix) const;
+ virtual void index(const GribDecoder& grib);
+ virtual void new_index(const GribDecoder& grib);
+
+ virtual int nearest(double, double, double&, double&);
+ Index nearest(double, double);
+ double west_;
+ double east_;
+
+ vector<vector<Index> > helper_;
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream& out) const { out << "GribInterpretor" << endl; }
+ map<double, map<double, int> > index_;
+ int indexLon_;
+ int indexLat_;
+ double indexStep_;
+ double minlat_;
+ double maxlat_;
+ double minlon_;
+ double maxlon_;
+
private:
+
//! Copy constructor - No copy allowed
GribInterpretor(const GribInterpretor&);
//! Overloaded << operator to copy - No copy allowed
diff --git a/src/decoders/GribRegularInterpretor.cc b/src/decoders/GribRegularInterpretor.cc
index a94eb5c..ebdcf51 100644
--- a/src/decoders/GribRegularInterpretor.cc
+++ b/src/decoders/GribRegularInterpretor.cc
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -45,1656 +45,2070 @@ GribRegularInterpretor::~GribRegularInterpretor() {
}
void GribInterpretor::longitudesSanityCheck(double& west, double& east) const {
- // make sure that the west longitudes is always inferior to teh East longitudes and always
- // betwwen -180 and 360...
+ // make sure that the west longitudes is always inferior to teh East longitudes and always
+ // betwwen -180 and 360...
- while (east <= west) {
- // We add 360 to the east ...
- east += 360;
- }
+ while (east <= west) {
+ // We add 360 to the east ...
+ east += 360;
+ }
- // We reposition if needed
+ // We reposition if needed
- while (east > 360) {
- west -= 360.;
- east -= 360.;
- }
+ while (east > 360) {
+ west -= 360.;
+ east -= 360.;
+ }
}
void GribInterpretor::scaling(const GribDecoder& grib, double& scaling,
- double& offset) const {
- string originalUnits, derivedUnits;
- this->scaling(grib, scaling, offset, originalUnits, derivedUnits);
+ double& offset) const {
+ string originalUnits, derivedUnits;
+ this->scaling(grib, scaling, offset, originalUnits, derivedUnits);
}
-void GribInterpretor::scaling(const GribDecoder& grib, double& scaling,
- double& offset, string& originalUnits, string& derivedUnits) const {
- scaling = 1;
- offset = 0;
-
- // First check that they are not derived fields!
-
- if (grib.scaling_ || grib.derived_scaling_) {
- long derived = grib.getLong("generatingProcessIdentifier");
-
- if ((derived != 254 && grib.scaling_)
- || (derived == 254 && grib.derived_scaling_)) {
- // The key 'paramId' embodies a number of features such as centre, parameter,
- // level, etc. This means that we should not need to worry about table
- // numbers, etc as we did with GRIBEX. However, it's not entirely clear
- // what we can do with non-ECMWF data, as we don't seem to have tables
- // giving scaling factors & offsets for such data. The code, as originally
- // written here takes a table-based approach, but this will probably
- // become redundant. What we really need is something more based on paramIds.
- // In the meantime, we will take the paramIds as if they are from ECMWF data.
- // In practice, this means pretending that all data is from
- // centre=98,table=128.
-
- long table = 128; // hard-coded in case of GRIB 2
- long centre = 98; // hard-coded in case of GRIB 2
-
- //long edition = grib.getLong("edition");
- //
- //if (edition == 1)
- //{
- // table = grib.getLong("table2Version");
- // centre = grib.getLong("centre");
- //}
- //else
- //{
- // // GRIB 2 does not use the table-based approach, so we just hope that this will
- // // work with most data if we use the standard ECMWF tables...
- //}
-
- long id = grib.getLong("paramId");
-
- try {
- const ParamDef& paramdef = LocalTable::localInfo(id, table,
- centre);
- scaling = paramdef.scaling();
- offset = paramdef.offset();
- originalUnits = paramdef.originalUnit();
- derivedUnits = paramdef.derivedUnit();
- } catch (...) {
- MagLog::warning()
- << " Can not find information for the parameter [" << id
- << "." << table << "]\n";
- }
- }
- } else {
- scaling = grib.scaling_factor_;
- offset = grib.scaling_offset_;
- }
- // Add a sanity check : the factor can not be 0..
- if (scaling == 0)
- scaling = 1;
+/// @brief The usual PI/180 constant
+static const double DEG_TO_RAD = 0.017453292519943295769236907684886;
+/// @brief Earth's quatratic mean radius for WGS-84
+static const double EARTH_RADIUS_IN_METERS = 6372797.560856;
+
+/** @brief Computes the arc, in radian, between two WGS-84 positions.
+ *
+ * The result is equal to <code>Distance(from,to)/EARTH_RADIUS_IN_METERS</code>
+ * <code>= 2*asin(sqrt(h(d/EARTH_RADIUS_IN_METERS )))</code>
+ *
+ * where:<ul>
+ * <li>d is the distance in meters between 'from' and 'to' positions.</li>
+ * <li>h is the haversine function: <code>h(x)=sin²(x/2)</code></li>
+ * </ul>
+ *
+ * The haversine formula gives:
+ * <code>h(d/R) = h(from.lat-to.lat)+h(from.lon-to.lon)+cos(from.lat)*cos(to.lat)</code>
+ *
+ * @sa http://en.wikipedia.org/wiki/Law_of_haversines
+ */
+double distance(double lat1, double lon1, double lat2, double lon2) {
+ double latitudeArc = (lat1 - lat2) * DEG_TO_RAD;
+ double longitudeArc = (lon1 - lon2) * DEG_TO_RAD;
+ double latitudeH = sin(latitudeArc * 0.5);
+ latitudeH *= latitudeH;
+ double lontitudeH = sin(longitudeArc * 0.5);
+ lontitudeH *= lontitudeH;
+ double tmp = cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD);
+ return EARTH_RADIUS_IN_METERS* (2.0 * asin(sqrt(latitudeH + tmp*lontitudeH)));
}
-void GribInterpretor::scaling(const GribDecoder& grib, Matrix** matrix) const {
- double factor, offset;
+void GribInterpretor::new_index(const GribDecoder& grib)
+{
+ //Use the grib Iterator to create the index
+
+ grib_handle* handle = grib.handle();
+
+
+ int error;
+
+ grib_iterator* iter = grib_iterator_new(handle, 0, &error);
+
+ double lat1, lon1, lat2, lon2, val;
+ grib_iterator_next(iter, &lat1, &lon1, &val) ;
+ grib_iterator_next(iter, &lat2, &lon2, &val) ;
+
+
+
+ grib_iterator_delete(iter);
+ // Get the fisrt 2 points ...
+
+
+ indexStep_ = distance(lat1, lon1, lat2, lon2) * 4;
+ indexStep_ = 0.5;
+
+ indexLon_ = 360./indexStep_;
+ indexLat_ = 180./indexStep_;
+
+
+/* scanning mode :
+ bit value meaning
+ 1 0 Points scan in +i direction
+ 1 1 Points scan in -i direction
+ 2 0 Points scan in -j direction
+ 2 1 Points scan in +j direction
+ 3 0 Adjacent points in i direction are consecutive
+ 3 1 Adjacent points in j direction are consecutive
+*/
+ if ( grib.getLong("jScansPositively") == 1 || grib.getLong("iScansPositively") == 0 ) {
+ MagLog::error() << " Scanning mode not yet supported" << endl;
+ return;
+ }
+
+ helper_ = vector<vector<Index> >((indexLon_+1)*(indexLat_+1), vector<Index>());
+
+ iter = grib_iterator_new(handle, 0, &error);
+
+
+ double lat, lon, u;
+ int ilat, ilon;
+ {
+
+ Timer timer("index", "index");
+ int i = 0;
+ bool flag_error = true;
+ //prepare enveloppe
+ minlon_ = 360;
+ maxlon_ = 0;
+ minlat_ = 90;
+ maxlat_ = -90;
+
+ while (grib_iterator_next(iter, &lat, &lon, &u) ) {
+ // Send a warning if lat lon are not in the expected rangs :
+ if ( lat < -90 || lat > 90 || lon < -180 || lon > 360) {
+ if ( flag_error ) {
+ MagLog::warning() << "Check Grib Iterator: Position is not in the expected range [" << lat << ", " << lon << "]" << endl;
+ flag_error = false;
+ }
+ continue;
+ }
+
+
+ if ( minlat_ > lat) minlat_ = lat;
+ if ( maxlat_ < lat) maxlat_ = lat;
+ if ( minlon_ > lon) minlon_ = lon;
+ if ( maxlon_ < lon) maxlon_ = lon;
+
+ if ( lon < 0 ) lon +=360.;
+ ilat = floor((lat+90)/indexStep_);
+ ilon = floor(lon/indexStep_);
+
+
+
+ helper_[ilat * indexLon_ + ilon].push_back(Index(i, lat, lon));
+
+ i++;
+ }
+
+
+ west_ = 0;
+ east_ = 360.;
+ grib_iterator_delete(iter);
+ }
- scaling(grib, factor, offset);
- (*matrix)->multiply(factor);
- (*matrix)->plus(offset);
}
-void GribInterpretor::raw(GribDecoder& grib,
- const Transformation& transformation,
- vector<pair<double, vector<pair<double, CustomisedPoint*> > > >& points,
- double& minlon, double& maxlon) const
+
+
+Index GribInterpretor::nearest(double ulat, double ulon)
{
- Timer timer("grib", "raw");
- double factor, offset;
- scaling(grib, factor, offset);
- int err;
- string uname, vname;
- grib_handle* uc = grib.uHandle(uname);
- grib_handle* vc = grib.vHandle(vname);
- long nblon = grib.getLong("numberOfPointsAlongAParallel");
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+ Index index(-1, 0, 0);
+ if ( ulat < minlat_ )
+ return index;
+ if ( ulat > maxlat_ )
+ return index;
+ bool out = true;
+ if ( ulon >= minlon_ && ulon <= maxlon_)
+ out = false;
+ if ( ulon-360 >= minlon_ && ulon-360 <= maxlon_)
+ out = false;
- points.reserve(nblat);
+ if ( out )
+ return index;
- grib_iterator* uiter = grib_iterator_new(uc, 0, &err);
- grib_iterator* viter = grib_iterator_new(vc, 0, &err);
- double missing = grib.getDouble("missingValue");
+
+ if ( ulat == -1000. || ulon == -1000.)
+ return index;
+ if ( ulat >= 90 || ulat <= -90)
+ return index;
- double lat, lon, u, v;
- double last = -99999999;
- minlon = 999999;
- maxlon = -999999;
- while (grib_iterator_next(uiter, &lat, &lon, &u)
- && grib_iterator_next(viter, &lat, &lon, &v)) {
- if (transformation.in(lon, lat) || transformation.in(lon - 360, lat)) {
- if (minlon > lon)
- minlon = lon;
- if (maxlon < lon)
- maxlon = lon;
- if (u != missing)
- u = (u * factor) + offset;
- if (v != missing)
- v = (v * factor) + offset;
- if (lat != last) {
- last = lat;
- points.push_back(
- make_pair(lat,
- vector<pair<double, CustomisedPoint*> >()));
- points.back().second.reserve(nblat * 2);
+ int ilat = floor((ulat+90)/indexStep_);
+ int ilon = floor(ulon/indexStep_);
+ int lat1, lat2;
- }
+ if ( ilon == indexLon_ )
+ ilon = 0;
- CustomisedPoint* point = new CustomisedPoint(lon, lat, "");
- point->insert(make_pair(uname, u));
- point->insert(make_pair(vname, v));
- points.back().second.push_back(make_pair(lon, point));
- }
- }
- grib_iterator_delete(viter);
- grib_iterator_delete(uiter);
+ lat1 = (ilat==0) ? ilat : ilat - 1;
+ lat2 = (ilat == indexLat_) ? ilat : ilat + 1;
- for (vector<pair<double, vector<pair<double, CustomisedPoint*> > > >::iterator ilat =
- points.begin(); ilat != points.end(); ++ilat) {
- vector < pair<double, CustomisedPoint*> > &lons = ilat->second;
+ // now make sure that we have
- CustomisedPoint* first = lons.front().second;
- ;
- CustomisedPoint* last = lons.back().second;
- //if (last->longitude() - first->longitude() > XResolution(grib)) {
- CustomisedPoint* dup = new CustomisedPoint(first->longitude() + 360,first->latitude(), "");
- dup->insert(make_pair("x_component", (*first)["x_component"]));
- dup->insert(make_pair("y_component", (*first)["y_component"]));
- lons.push_back(make_pair(dup->longitude(), dup));
- //}
- }
-}
-void GribInterpretor::raw(const GribDecoder& grib,
- const Transformation& transformation, const string& key,
- map<double, map<double, CustomisedPoint*> >& points) const {
- Timer timer("grib", "raw");
- double factor, offset;
- scaling(grib, factor, offset);
- int err;
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
- map<double, map<double, CustomisedPoint*> >::iterator ilat;
- map<double, CustomisedPoint*>::iterator ilon;
- grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
- double missing = grib.getDouble("missingValue");
+
- double lat, lon, value;
+ double nearest = std::numeric_limits<double>::max();
+ for ( int clat = lat1; clat <= lat2; clat++ ) {
+ // find the first non empty cell
+ // Try ilon ..
+ vector<Index> points = helper_[clat * indexLon_ + ilon];
+ set<int> lonn;
- /* Loop on all the lat/lon/values. */
- while (grib_iterator_next(iter, &lat, &lon, &value)) {
+ lonn.insert(ilon);
+ bool empty = true;
+ int count = 0;
+ // Try the first cell not empty on the left
+ int lon = ilon-1;
- if (transformation.in(lon, lat) || transformation.in(lon - 360, lat)) {
- if (value != missing)
- value = (value * factor) + offset;
+ while ( empty && count < indexLon_) {
+ if ( lon < 0 ) {
+ lon = indexLon_ -1;
+ }
- ilat = points.find(lat);
- if (ilat == points.end()) {
+ points = helper_[clat * indexLon_ + lon];
+ if ( !points.empty() ) {
+ lonn.insert(lon);
+ empty = false;
+ }
+ count++;
+ lon--;
+ }
+ empty = true;
+ count = 0;
+ lon = ilon +1;
+ // try the first cell not empty on the right
+ while ( empty && count < indexLon_ ) {
+ if ( lon >= indexLon_ ) {
+ lon = 0;
+ }
- points.insert(make_pair(lat, map<double, CustomisedPoint*>()));
- ilat = points.find(lat);
+ points = helper_[clat * indexLon_ + lon];
+ if ( !points.empty() ) {
+ lonn.insert(lon);
+ empty = false;
+ }
+ count++;
+ lon++;
+ }
- }
- ilon = ilat->second.find(lon);
- if (ilon == ilat->second.end()) {
- CustomisedPoint* pt = new CustomisedPoint(lon, lat, "");
- pt->missing(true);
- ilat->second.insert(make_pair(lon, pt));
- ilon = ilat->second.find(lon);
- }
- ilon->second->insert(make_pair(key, value));
+ for ( set<int>::iterator lon = lonn.begin(); lon != lonn.end(); ++lon ) {
- }
+ vector<Index> points = helper_[clat * indexLon_ + (*lon)];
- }
- /* At the end the iterator is deleted to free memory. */
- grib_iterator_delete(iter);
-}
-/*!
- Class information are given to the output-stream.
- */
-void GribRegularInterpretor::print(ostream& out) const {
- out << "GribRegularInterpretor[";
- out << "]";
-}
+ for (vector<Index>::iterator point = points.begin(); point != points.end(); ++point) {
+ Index i = *point;
-void GribRegularInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix, const Transformation&) const {
- interpretAsMatrix(grib, matrix);
-}
+ double dist = distance(ulat, ulon, i.lat_, i.lon_);
-void GribRegularInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
- Timer timer("gribapi", " read grib");
- MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
- long nblon = grib.getLong("numberOfPointsAlongAParallel");
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
-
- if (*matrix == 0)
- *matrix = new Matrix(nblat, nblon);
-
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
-
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
- double missing = INT_MAX;
- grib.setDouble("missingValue", missing);
- (*matrix)->missing(missing);
- (*matrix)->akimaEnabled();
-
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
- ;
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- ;
- longitudesSanityCheck(west, east);
-
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
- << ", " << south << "]" << "\n";
- double loni = longitudeIncrement(grib);
-
- double lon = (east - west) / (nblon - 1);
-
- MagLog::dev() << "increment -->" << loni << " (from->" << west << " to-->"
- << west + (nblon - 1) * loni << ")" << endl;
- MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
- << west + (nblon - 1) * lon << ")" << endl;
-
- latitudes(grib, (*matrix)->rowsAxis());
-
- double x = west;
- for (int i = 0; i < nblon; i++) {
- (*matrix)->columnsAxis().push_back(x);
- x = west + (i + 1) * lon;
- }
-
- (*matrix)->setMapsAxis();
-
- long jPointsAreConsecutive = grib.getLong("jPointsAreConsecutive");
-
- try {
- (*matrix)->resize(nb);
- size_t aux = size_t(nb);
-
- // if jPointsAreConsecutive=1 then the values represent columns of data instead
- // of rows, so we have to 'reshape' the array so that it is reorganised into rows.
-
- if (jPointsAreConsecutive) {
- vector<double> *d = new vector<double>(nb); // temporary array
- double *d1 = &d->front(); // temporary array pointer
- double *d2 = &(*matrix)->front(); // final array
-
- grib_get_double_array(grib.id(), "values", d1, &aux);
-
- for (int i = 0; i < nblon; i++) {
- for (int j = 0; j < nblat; j++) {
- d2[j * nblon + i] = d1[i * nblat + j];
- }
- }
-
- delete d;
- } else // otherwise, just copy the array of values as they are
- {
- grib_get_double_array(grib.id(), "values", &(*matrix)->front(),
- &aux);
- }
-
- (*matrix)->missing(missing);
-
- } catch (...) {
- throw MagicsException("GribRegularInterpretor - Not enough memory");
- }
-}
+ if ( dist < nearest ) {
+ nearest = dist;
+ index = i;
-void GribRegularInterpretor::latitudes(const GribDecoder& grib,
- vector<double>& latitudes) const {
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ }
+ }
+
+ }
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
- int scanning = grib.getLong("jScansPositively") ? 1 : -1;
- double lat = scanning * grib.getDouble("jDirectionIncrementInDegrees");
- double y = north;
- for (int i = 0; i < nblat; i++) {
- latitudes.push_back(y);
- y += lat;
- }
+ }
+ //if ( index.lon_ < 0 )
+ // index.lon_ += 360.;
+
+ return index;
}
-void GribRegularGaussianInterpretor::latitudes(const GribDecoder& grib,
- vector<double>& latitudes) const {
- long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
- double array[2 * res];
- grib_get_gaussian_latitudes(res, array);
- double first = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double last = grib.getDouble("latitudeOfLastGridPointInDegrees");
- ;
- // get the scanning mode !
- double north = first;
- double south = last;
- long scanning = grib.getLong("jScansPositively");
- ;
- if (scanning == 1) {
- north = last;
- south = first;
- }
-
- for (int i = 0; i < 2 * res; i++) {
- if (same(array[i], north, 10e-2)) {
- latitudes.push_back(array[i]);
- continue;
- }
- if (same(array[i], south, 10e-2)) {
- latitudes.push_back(array[i]);
- continue;
- }
- if (array[i] < north && array[i] > south)
- latitudes.push_back(array[i]);
- }
-
- if (scanning == 1)
- std::reverse(latitudes.begin(), latitudes.end());
+
+
+void GribInterpretor::scaling(const GribDecoder& grib, double& scaling,
+ double& offset, string& originalUnits, string& derivedUnits) const {
+ scaling = 1;
+ offset = 0;
+
+ // First check that they are not derived fields!
+
+ if (grib.scaling_ || grib.derived_scaling_) {
+ long derived = grib.getLong("generatingProcessIdentifier");
+
+ if ((derived != 254 && grib.scaling_)
+ || (derived == 254 && grib.derived_scaling_)) {
+ // The key 'paramId' embodies a number of features such as centre, parameter,
+ // level, etc. This means that we should not need to worry about table
+ // numbers, etc as we did with GRIBEX. However, it's not entirely clear
+ // what we can do with non-ECMWF data, as we don't seem to have tables
+ // giving scaling factors & offsets for such data. The code, as originally
+ // written here takes a table-based approach, but this will probably
+ // become redundant. What we really need is something more based on paramIds.
+ // In the meantime, we will take the paramIds as if they are from ECMWF data.
+ // In practice, this means pretending that all data is from
+ // centre=98,table=128.
+
+ long table = 128; // hard-coded in case of GRIB 2
+ long centre = 98; // hard-coded in case of GRIB 2
+
+ //long edition = grib.getLong("edition");
+ //
+ //if (edition == 1)
+ //{
+ // table = grib.getLong("table2Version");
+ // centre = grib.getLong("centre");
+ //}
+ //else
+ //{
+ // // GRIB 2 does not use the table-based approach, so we just hope that this will
+ // // work with most data if we use the standard ECMWF tables...
+ //}
+
+ long id = grib.getLong("paramId");
+
+ try {
+ const ParamDef& paramdef = LocalTable::localInfo(id, table,
+ centre);
+ scaling = paramdef.scaling();
+ offset = paramdef.offset();
+ originalUnits = paramdef.originalUnit();
+ derivedUnits = paramdef.derivedUnit();
+ } catch (...) {
+ MagLog::warning()
+ << " Can not find information for the parameter [" << id
+ << "." << table << "]\n";
+ }
+ }
+ } else {
+ scaling = grib.scaling_factor_;
+ offset = grib.scaling_offset_;
+ }
+ // Add a sanity check : the factor can not be 0..
+ if (scaling == 0)
+ scaling = 1;
}
-double GribRegularInterpretor::longitudeIncrement(
- const GribDecoder& grib) const {
- int scanning = grib.getLong("iScansNegatively") ? -1 : 1;
- return scanning * grib.getDouble("iDirectionIncrementInDegrees");
+void GribInterpretor::scaling(const GribDecoder& grib, Matrix** matrix) const {
+ double factor, offset;
+
+ scaling(grib, factor, offset);
+ (*matrix)->multiply(factor);
+ (*matrix)->plus(offset);
+}
+void GribInterpretor::index(const GribDecoder& grib)
+{
+ throw MethodNotYetImplemented("GribInterpretor::index");
}
-PaperPoint GribInterpretor::reference(const GribDecoder& grib, const Transformation& transformation)
+
+
+int GribInterpretor::nearest(double lon, double lat, double& nlon, double& nlat)
{
- double lon = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double lat = grib.getDouble("latitudeOfFirstGridPointInDegrees");
-
- UserPoint point(grib.getDouble("longitudeOfFirstGridPointInDegrees"),
- grib.getDouble("latitudeOfFirstGridPointInDegrees"));
-
- if (transformation.in(point))
- return transformation(point);
- int err;
- grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
-
- double value;
- /* Loop on all the lat/lon/values. */
- while (grib_iterator_next(iter, &lat, &lon, &value)) {
- point = UserPoint(lon, lat);
- if (transformation.in(point)) {
- grib_iterator_delete(iter);
- return transformation(point);
- }
- }
-
- /* At the end the iterator is deleted to free memory. */
- grib_iterator_delete(iter);
- return PaperPoint(transformation.getMinPCX(), transformation.getMinPCY());
+
+ map<double, map<double, int> >::iterator y1, y2, y;
+ map<double, int>::iterator x1, x2, x;
+
+ if ( lat < index_.begin()->first)
+ return -1;
+ if ( lat > index_.rbegin()->first)
+ return -1;
+ y2 = index_.lower_bound(lat);
+ if ( y2 == index_.begin() ) {
+ y = y2;
+ }
+ else {
+ y1 = y2;
+ y1--;
+ y = (lat - y1->first < y2->first - lat) ? y1 : y2;
+ }
+ nlat = y->first;
+
+
+
+ if ( lon < y->second.begin()->first)
+ return -1;
+ if ( lon > y->second.rbegin()->first)
+ return -1;
+ x2 = y->second.lower_bound(lon);
+ if ( x2 == y->second.begin() ) {
+ x = x2;
+ }
+ else {
+ x1 = x2;
+ x1--;
+ x = (lon - x1->first < x2->first - lon) ? x1 : x2;
+ }
+ nlon = x->first;
+ return x->second;
+
}
-void GribRegularInterpretor::interpretAsRaster(const GribDecoder& grib,
- RasterData& raster, const Transformation& transformation) const {
- MagLog::dev() << "GribRegularInterpretor::interpretAsRaster" << "\n";
+void GribInterpretor::raw(GribDecoder& grib,
+ const Transformation& transformation,
+ vector<pair<double, vector<pair<double, CustomisedPoint*> > > >& points,
+ double& minlon, double& maxlon) const
+{
+ Timer timer("grib", "raw");
+ double factor, offset;
+ scaling(grib, factor, offset);
+ int err;
- BoxMatrixHandler box(const_cast<GribDecoder*>(&grib)->matrix(),
- transformation);
+ string uname, vname;
- int nblon = box.columns();
- int nblat = box.rows();
- double east = box.column(0, nblon - 1);
- double west = box.column(0, 0);
- double south = box.row(0, 0);
- double north = box.row(nblat - 1, 0);
+ grib_handle* uc = grib.uHandle(uname);
+ grib_handle* vc = grib.vHandle(vname);
- raster.setUpperRightCorner(east, north);
- raster.setLowerLeftCorner(west, south);
- double lon = (east - west) / (nblon - 1);
- double lat = (north - south) / (nblat - 1);
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
- raster.setXResolution(lon);
- raster.setYResolution(lat);
+ points.reserve(nblat);
- raster.setColumns(nblon);
- raster.setRows(nblat);
- //
- raster.setProjection(new TeLatLong(TeDatum()));
+ grib_iterator* uiter = grib_iterator_new(uc, 0, &err);
+ grib_iterator* viter = grib_iterator_new(vc, 0, &err);
+ double missing = grib.getDouble("missingValue");
- raster.reserve(nblon * nblat);
+ double lat, lon, u, v;
+ double last = -99999999;
- for (int j = nblat - 1; j >= 0; j--)
- for (int i = 0; i < nblon; i++)
- raster.push_back(box(j, i));
-}
+ minlon = 999999;
+ maxlon = -999999;
-void GribReducedGaussianInterpretor::interpretAsRaster(const GribDecoder& grib,
- RasterData& raster, const Transformation& transformation) const {
- MagLog::dev() << "GribRegularInterpretor::interpretAsRaster" << "\n";
- Timer timer("grib api", "read grib");
- BoxMatrixHandler box(const_cast<GribDecoder*>(&grib)->matrix(),
- transformation);
-
- int nblon = box.columns();
- int nblat = box.rows();
- double east = box.column(0, nblon - 1);
- double west = box.column(0, 0);
- double south = box.row(0, 0);
- double north = box.row(nblat - 1, 0);
-
- raster.setUpperRightCorner(east, north);
- raster.setLowerLeftCorner(west, south);
-
- double lon = (east - west) / (nblon - 1);
- double lat = (north - south) / (nblat - 1);
-
- raster.setXResolution(lon);
- raster.setYResolution(lat);
-
- raster.setColumns(nblon);
- raster.setRows(nblat);
- //
- raster.setProjection(new TeLatLong(TeDatum()));
-
- raster.reserve(nblon * nblat);
-
- for (int j = nblat - 1; j >= 0; j--)
- for (int i = 0; i < nblon; i++)
- raster.push_back(box(j, i));
-}
+ while (grib_iterator_next(uiter, &lat, &lon, &u)
+ && grib_iterator_next(viter, &lat, &lon, &v)) {
-void GribReducedGaussianInterpretor::print(ostream& out) const {
- out << "GribRegularInterpretor[";
- out << "]";
-}
+ if (transformation.in(lon, lat) || transformation.in(lon - 360, lat)) {
+ if (minlon > lon)
+ minlon = lon;
+ if (maxlon < lon)
+ maxlon = lon;
+ if (u != missing)
+ u = (u * factor) + offset;
+ if (v != missing)
+ v = (v * factor) + offset;
-void GribReducedGaussianInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix, const Transformation& transformation) const {
- interpretAsMatrix(grib, matrix);
+ if (lat != last) {
+ last = lat;
+ points.push_back(
+ make_pair(lat,
+ vector<pair<double, CustomisedPoint*> >()));
+ points.back().second.reserve(nblat * 2);
-}
+ }
-double GribReducedLatLonInterpretor::XResolution(
- const GribDecoder& grib) const {
- long res = grib.getLong("Nj");
+ CustomisedPoint* point = new CustomisedPoint(lon, lat, "");
+ point->insert(make_pair(uname, u));
+ point->insert(make_pair(vname, v));
+ points.back().second.push_back(make_pair(lon, point));
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- ;
+ }
- longitudesSanityCheck(west, east);
+ }
- return (east - west) / (2 * res);
-}
-double GribReducedGaussianInterpretor::XResolution(
- const GribDecoder& grib) const {
- long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ grib_iterator_delete(viter);
+ grib_iterator_delete(uiter);
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- ;
+ for (vector<pair<double, vector<pair<double, CustomisedPoint*> > > >::iterator ilat =
+ points.begin(); ilat != points.end(); ++ilat) {
+ vector < pair<double, CustomisedPoint*> > &lons = ilat->second;
- longitudesSanityCheck(west, east);
- return (east - west) / (4 * res);
-}
+ CustomisedPoint* first = lons.front().second;
+ ;
-void GribReducedGaussianInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
- MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
- MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
-
- Timer timer("gribapi", " read grib");
- *matrix = new Matrix();
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
- bool interpolate = grib.interpolate();
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
- double missing = std::numeric_limits<double>::max();
- grib.setDouble("missingValue", missing);
-
- (*matrix)->missing(missing);
- (*matrix)->akimaEnabled();
-
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- double plp = grib.getDouble("PLPresent");
- long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
-
- longitudesSanityCheck(west, east);
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
- << ", " << south << "]" << "\n";
- MagLog::dev() << "PLPresent---> " << plp << "\n";
- MagLog::dev() << "Res---> " << res << "\n";
-
- double pl[2 * res];
- size_t aux = 2 * res;
- grib_get_double_array(grib.id(), "pl", pl, &aux);
- int nblon = 0;
- for ( int i = 0; i < aux; i++)
- if ( pl[i] > nblon) nblon = pl[i];
-
- double array[2 * res];
- grib_get_gaussian_latitudes(res, array);
-
- MagLog::dev() << "Resolution ---> " << nblon << "???" << 4 * res << "\n";
-
- // We have to determine if the field is global!
- if (north - south > 175.) {
- east = west + 360.;
- }
-
- // compute the number of points we'll be adding to the matrix so that we can
- // allocate them in one go, rather than allowing the STL to re-allocate
- // when we reach the capacity
- (*matrix)->reserve(aux * nblon);
-
- double *data = new double[nb];
-
- size_t aux2 = size_t(nb);
-
- double width = east - west;
- double step = (width) / (nblon);
-
- grib_get_double_array(grib.id(), "values", data, &aux2);
-
- int d = 0;
- for (size_t i = 0; i < aux; i++) {
- vector<double> p;
- for (int ii = 0; ii < pl[i]; ii++) {
- p.push_back(data[d]);
- d++;
- }
-
- double lon = west;
- unsigned int p1 = 0;
- unsigned int p2 = 1;
- double lon1 = west;
- double lon2 = lon1 + (width / (p.size()));
-
- for (int x = 0; x < nblon; x++) {
-
- if (lon >= lon2) {
- p1++;
- p2++;
- lon1 = lon2;
- lon2 += (width) / (p.size());
- }
- double d1 = (lon2 - lon) / (lon2 - lon1);
- double d2 = 1 - d1;
- double val;
-
- assert(p1 < p.size());
- if (p2 == p.size()) {
- (*matrix)->push_back(p[p1]);
- } else {
- if (interpolate) {
- if (p[p1] == missing || p[p2] == missing)
- val = missing;
- else
- val = (p[p1] * d1) + (p[p2] * d2);
- } else {
- val = (d2 < 0.5) ? p[p1] : p[p2];
-
- }
- (*matrix)->push_back(val);
- }
- lon += step;
- }
-
- }
-
- delete[] data;
-
- for (int x = 0; x < nblon; x++) {
- (*matrix)->columnsAxis().push_back(west + (x * step));
- }
-
-
- for (int i = 0; i < 2 * res; i++) {
-
- (*matrix)->rowsAxis().push_back(array[i]);
- }
- (*matrix)->setMapsAxis();
-}
+ //if (last->longitude() - first->longitude() > XResolution(grib)) {
+ CustomisedPoint* dup = new CustomisedPoint(first->longitude() + 360,first->latitude(), "");
+ dup->insert(make_pair("x_component", (*first)["x_component"]));
+ dup->insert(make_pair("y_component", (*first)["y_component"]));
+ lons.push_back(make_pair(dup->longitude(), dup));
+ //}
+ }
-void GribReducedLatLonInterpretor::print(ostream& out) const {
- out << "GribReducedLatLonInterpretor[";
- out << "]";
}
-void GribReducedLatLonInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
+void GribInterpretor::raw(const GribDecoder& grib,
+ const Transformation& transformation, const string& key,
+ map<double, map<double, CustomisedPoint*> >& points) const {
+ Timer timer("grib", "raw");
+ double factor, offset;
+ scaling(grib, factor, offset);
+ int err;
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ map<double, map<double, CustomisedPoint*> >::iterator ilat;
+ map<double, CustomisedPoint*>::iterator ilon;
- Timer timer("gribapi", " read grib");
- *matrix = new Matrix();
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
+ grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
+ double missing = grib.getDouble("missingValue");
+ double lat, lon, value;
- double missing = std::numeric_limits<double>::max();
- grib.setDouble("missingValue", missing);
+ /* Loop on all the lat/lon/values. */
+ while (grib_iterator_next(iter, &lat, &lon, &value)) {
- (*matrix)->missing(missing);
- (*matrix)->akimaEnabled();
+ if (transformation.in(lon, lat) || transformation.in(lon - 360, lat)) {
+ if (value != missing)
+ value = (value * factor) + offset;
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ilat = points.find(lat);
+ if (ilat == points.end()) {
+
+ points.insert(make_pair(lat, map<double, CustomisedPoint*>()));
+ ilat = points.find(lat);
+
+ }
+ ilon = ilat->second.find(lon);
+
+ if (ilon == ilat->second.end()) {
+ CustomisedPoint* pt = new CustomisedPoint(lon, lat, "");
+ pt->missing(true);
+ ilat->second.insert(make_pair(lon, pt));
+ ilon = ilat->second.find(lon);
+
+ }
+ ilon->second->insert(make_pair(key, value));
+
+ }
+
+ }
+
+ /* At the end the iterator is deleted to free memory. */
+ grib_iterator_delete(iter);
+
+}
+/*!
+ Class information are given to the output-stream.
+ */
+void GribRegularInterpretor::print(ostream& out) const {
+ out << "GribRegularInterpretor[";
+ out << "]";
+}
- longitudesSanityCheck(west, east);
- size_t res = grib.getLong("Nj");
+void GribRegularInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix, const Transformation&) const {
+ interpretAsMatrix(grib, matrix);
+}
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
- << ", " << south << "]" << "\n";
- MagLog::dev() << "Res---> " << res << "\n";
+void GribRegularInterpretor::index(const GribDecoder& grib)
+{
+ if ( !index_.empty() )
+ return;
+ long nblon = grib.getLong("numberOfPointsAlongAParallel");
- double pl[res];
+ west_ = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
- int scanning = grib.getLong("jScansPositively") ? 1 : -1;
- double lat = scanning * grib.getDouble("jDirectionIncrementInDegrees");
+ east_ = grib.getDouble("longitudeOfLastGridPointInDegrees");
- grib_get_double_array(grib.id(), "pl", pl, &res);
+ longitudesSanityCheck(west_, east_);
- double *data = new double[nb];
- size_t aux2 = size_t(nb);
+ double lon = (east_ - west_) / (nblon - 1);
- int nblon = 0;
- for ( int i = 0; i < res; i++)
- if (nblon < pl[i] )
- nblon = pl[i];
+ vector<double> latitudes;
+ vector<double> longitudes;
- double width = east - west;
- double step = width / nblon;
+ this->latitudes(grib, latitudes);
- // We have to determine if the field is global!
- // We have to determine if the field is global!
- bool global = east - west > 360 - 5 * step;
+ double x = west_;
+ for (int i = 0; i < nblon; i++) {
+ longitudes.push_back(x);
+ x = west_ + (i + 1) * lon;
+ }
- if (global) {
- east = west + 360;
- width = east - west;
- step = width / nblon;
- }
- grib_get_double_array(grib.id(), "values", data, &aux2);
- int d = 0;
- for (size_t i = 0; i < res; i++) {
+ long jPointsAreConsecutive = grib.getLong("jPointsAreConsecutive");
+ int index = 0;
+ try {
+ if (jPointsAreConsecutive) {
+ for ( vector<double>::iterator lat = latitudes.begin(); lat != latitudes.end(); ++lat) {
+ index_.insert(make_pair(*lat, map<double, int>()));
+ }
+ for ( vector<double>::iterator lon = longitudes.begin(); lon != longitudes.end(); ++lon) {
- if (pl[i] == 0) {
- // add missing data
- for (int x = 0; x < nblon; x++)
- (*matrix)->push_back(missing);
- }
- else {
- unsigned int p1 = 0;
- vector<double> p;
- vector<double> lons;
+ for ( vector<double>::iterator lat = latitudes.begin(); lat != latitudes.end(); ++lat) {
- double datastep = width / pl[i];
- for (int ii = 0; ii < pl[i]; ii++) {
- p.push_back(data[d]);
- lons.push_back( west + (ii*datastep) );
+ index_[*lat].insert(make_pair(*lon, index));
+ index++;
+ }
+ }
+ }
+ else // otherwise, just copy the array of values as they are
+ {
+ for ( vector<double>::iterator lat = latitudes.begin(); lat != latitudes.end(); ++lat) {
+ index_.insert(make_pair(*lat, map<double, int>()));
+ for ( vector<double>::iterator lon = longitudes.begin(); lon != longitudes.end(); ++lon) {
+ index_[*lat].insert(make_pair(*lon, index));
+ index++;
+ }
+ }
+ }
- d++;
- }
- assert( p.size() == pl[i]);
+ }
+ catch (...) {
+ throw MagicsException("GribRegularInterpretor - Not enough memory");
+ }
- vector<double>::iterator val = p.begin();
- vector<double>::iterator lval = lons.begin();
- vector<double>::iterator nval = p.begin();
- nval++;
- vector<double>::iterator nlval = lons.begin();
- nlval++;
- for (int x = 0; x < nblon; x++) {
- double lon = west + (x*step);
+}
- if ( lon > *lval ) {
+void GribRegularInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix) const {
+ Timer timer("gribapi", " read grib");
+ MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
+ long nblon = grib.getLong("numberOfPointsAlongAParallel");
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+
+ if (*matrix == 0)
+ *matrix = new Matrix(nblat, nblon);
+
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ double missing = INT_MAX;
+ grib.setDouble("missingValue", missing);
+ (*matrix)->missing(missing);
+ (*matrix)->akimaEnabled();
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ ;
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ;
+ longitudesSanityCheck(west, east);
+
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
+ << ", " << south << "]" << "\n";
+ double loni = longitudeIncrement(grib);
+
+ double lon = (east - west) / (nblon - 1);
+
+ MagLog::dev() << "increment -->" << loni << " (from->" << west << " to-->"
+ << west + (nblon - 1) * loni << ")" << endl;
+ MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
+ << west + (nblon - 1) * lon << ")" << endl;
+
+ latitudes(grib, (*matrix)->rowsAxis());
+
+ double x = west;
+ for (int i = 0; i < nblon; i++) {
+ (*matrix)->columnsAxis().push_back(x);
+ x = west + (i + 1) * lon;
+ }
+
+ (*matrix)->setMapsAxis();
+
+ long jPointsAreConsecutive = grib.getLong("jPointsAreConsecutive");
+
+ try {
+ (*matrix)->resize(nb);
+ size_t aux = size_t(nb);
+
+ // if jPointsAreConsecutive=1 then the values represent columns of data instead
+ // of rows, so we have to 'reshape' the array so that it is reorganised into rows.
+
+ if (jPointsAreConsecutive) {
+ vector<double> *d = new vector<double>(nb); // temporary array
+ double *d1 = &d->front(); // temporary array pointer
+ double *d2 = &(*matrix)->front(); // final array
+
+ grib_get_double_array(grib.id(), "values", d1, &aux);
+
+ for (int i = 0; i < nblon; i++) {
+ for (int j = 0; j < nblat; j++) {
+ d2[j * nblon + i] = d1[i * nblat + j];
+ }
+ }
+
+ delete d;
+ } else // otherwise, just copy the array of values as they are
+ {
+ grib_get_double_array(grib.id(), "values", &(*matrix)->front(),
+ &aux);
+ }
+
+ (*matrix)->missing(missing);
+
+ } catch (...) {
+ throw MagicsException("GribRegularInterpretor - Not enough memory");
+ }
+}
- lval++;
- val++;
- if ( lval == lons.end() ) {
- val = p.begin();
- lval = lons.begin();
- }
- nval++;
- nlval++;
- if ( nlval == lons.end() ) {
- nval = p.begin();
- nlval = lons.begin();
- }
+void GribRegularInterpretor::latitudes(const GribDecoder& grib,
+ vector<double>& latitudes) const {
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- }
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+ int scanning = grib.getLong("jScansPositively") ? 1 : -1;
+ double lat = scanning * grib.getDouble("jDirectionIncrementInDegrees");
+ double y = north;
+ for (int i = 0; i < nblat; i++) {
+ latitudes.push_back(y);
+ y += lat;
+ }
+}
+void GribRegularGaussianInterpretor::latitudes(const GribDecoder& grib,
+ vector<double>& latitudes) const {
+ long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
+ double array[2 * res];
+ grib_get_gaussian_latitudes(res, array);
+ double first = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double last = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ ;
+ // get the scanning mode !
+ double north = first;
+ double south = last;
+ long scanning = grib.getLong("jScansPositively");
+ ;
+ if (scanning == 1) {
+ north = last;
+ south = first;
+ }
+
+ for (int i = 0; i < 2 * res; i++) {
+ if (same(array[i], north, 10e-2)) {
+ latitudes.push_back(array[i]);
+ continue;
+ }
+ if (same(array[i], south, 10e-2)) {
+ latitudes.push_back(array[i]);
+ continue;
+ }
+ if (array[i] < north && array[i] > south)
+ latitudes.push_back(array[i]);
+ }
+
+ if (scanning == 1)
+ std::reverse(latitudes.begin(), latitudes.end());
+}
- if ( *val == missing || *nval == missing)
- (*matrix)->push_back(*val);
- else {
+double GribRegularInterpretor::longitudeIncrement(
+ const GribDecoder& grib) const {
+ int scanning = grib.getLong("iScansNegatively") ? -1 : 1;
+ return scanning * grib.getDouble("iDirectionIncrementInDegrees");
+}
- double d1 = ( *nlval - lon) / (datastep);
- if ( d1 < 0 ) d1 = 1;
- double d2 = 1 - d1;
- (*matrix)->push_back( ( d1 * (*val)) + (d2 * (*nval)));
- }
+PaperPoint GribInterpretor::reference(const GribDecoder& grib, const Transformation& transformation)
+{
+ double lon = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double lat = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+
+ UserPoint point(grib.getDouble("longitudeOfFirstGridPointInDegrees"),
+ grib.getDouble("latitudeOfFirstGridPointInDegrees"));
+
+ if (transformation.in(point))
+ return transformation(point);
+ int err;
+ grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
+
+ double value;
+ /* Loop on all the lat/lon/values. */
+ while (grib_iterator_next(iter, &lat, &lon, &value)) {
+ point = UserPoint(lon, lat);
+ if (transformation.in(point)) {
+ grib_iterator_delete(iter);
+ return transformation(point);
+ }
+ }
+
+ /* At the end the iterator is deleted to free memory. */
+ grib_iterator_delete(iter);
+ return PaperPoint(transformation.getMinPCX(), transformation.getMinPCY());
+}
+void GribRegularInterpretor::interpretAsRaster(const GribDecoder& grib,
+ RasterData& raster, const Transformation& transformation) const {
+ MagLog::dev() << "GribRegularInterpretor::interpretAsRaster" << "\n";
+ BoxMatrixHandler box(const_cast<GribDecoder*>(&grib)->matrix(),
+ transformation);
+ int nblon = box.columns();
+ int nblat = box.rows();
+ double east = box.column(0, nblon - 1);
+ double west = box.column(0, 0);
+ double south = box.row(0, 0);
+ double north = box.row(nblat - 1, 0);
- }
- }
- }
+ raster.setUpperRightCorner(east, north);
+ raster.setLowerLeftCorner(west, south);
- delete[] data;
+ double lon = (east - west) / (nblon - 1);
+ double lat = (north - south) / (nblat - 1);
+ raster.setXResolution(lon);
+ raster.setYResolution(lat);
- for (int x = 0; x < nblon; x++) {
- (*matrix)->columnsAxis().push_back(west + (x * step));
- }
+ raster.setColumns(nblon);
+ raster.setRows(nblat);
+ //
+ raster.setProjection(new TeLatLong(TeDatum()));
- double y = north;
- for (long i = 0; i < nblat; i++) {
- (*matrix)->rowsAxis().push_back(y);
- y += lat;
- }
+ raster.reserve(nblon * nblat);
- (*matrix)->setMapsAxis();
+ for (int j = nblat - 1; j >= 0; j--)
+ for (int i = 0; i < nblon; i++)
+ raster.push_back(box(j, i));
}
-/*
- * Imported from Metview MvGrid...
- */
+void GribReducedGaussianInterpretor::interpretAsRaster(const GribDecoder& grib,
+ RasterData& raster, const Transformation& transformation) const {
+ MagLog::dev() << "GribRegularInterpretor::interpretAsRaster" << "\n";
+ Timer timer("grib api", "read grib");
+ BoxMatrixHandler box(const_cast<GribDecoder*>(&grib)->matrix(),
+ transformation);
+
+ int nblon = box.columns();
+ int nblat = box.rows();
+ double east = box.column(0, nblon - 1);
+ double west = box.column(0, 0);
+ double south = box.row(0, 0);
+ double north = box.row(nblat - 1, 0);
+
+ raster.setUpperRightCorner(east, north);
+ raster.setLowerLeftCorner(west, south);
+
+ double lon = (east - west) / (nblon - 1);
+ double lat = (north - south) / (nblat - 1);
+
+ raster.setXResolution(lon);
+ raster.setYResolution(lat);
+
+ raster.setColumns(nblon);
+ raster.setRows(nblat);
+ //
+ raster.setProjection(new TeLatLong(TeDatum()));
+
+ raster.reserve(nblon * nblat);
+
+ for (int j = nblat - 1; j >= 0; j--)
+ for (int i = 0; i < nblon; i++)
+ raster.push_back(box(j, i));
+}
-void GribRotatedInterpretor::print(ostream& out) const {
- out << "GribRotatedInterpretor[]";
+void GribReducedGaussianInterpretor::print(ostream& out) const {
+ out << "GribRegularInterpretor[";
+ out << "]";
}
-UserPoint GribLambertAzimutalInterpretor::unrotate(double lat,
- double lon) const {
+void GribReducedGaussianInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix, const Transformation& transformation) const {
+ interpretAsMatrix(grib, matrix);
- return UserPoint(lon, lat);
}
-pair<double, double> GribRotatedInterpretor::unrotate(double lat_y,
- double lon_x) const {
- const double cToRadians = M_PI / 180.0;
- double ZRADI = 1. / cToRadians;
- double ZSYCEN = sin(cToRadians * (southPoleLat_ + 90.));
- double ZCYCEN = cos(cToRadians * (southPoleLat_ + 90.));
- double ZSXROT = sin(cToRadians * lon_x);
- double ZCXROT = cos(cToRadians * lon_x);
- double ZSYROT = sin(cToRadians * lat_y);
- double ZCYROT = cos(cToRadians * lat_y);
- double ZSYREG = ZCYCEN * ZSYROT + ZSYCEN * ZCYROT * ZCXROT;
- ZSYREG = MAX(MIN(ZSYREG, +1.0), -1.0);
- double PYREG = asin(ZSYREG) * ZRADI;
- double ZCYREG = cos(PYREG * cToRadians);
- double ZCXMXC = (ZCYCEN * ZCYROT * ZCXROT - ZSYCEN * ZSYROT) / ZCYREG;
- ZCXMXC = MAX(MIN(ZCXMXC, +1.0), -1.0);
- double ZSXMXC = ZCYROT * ZSXROT / ZCYREG;
- double ZXMXC = acos(ZCXMXC) * ZRADI;
- if (ZSXMXC < 0.0)
- ZXMXC = -ZXMXC;
- double PXREG = ZXMXC + southPoleLon_;
- return std::make_pair(PYREG, PXREG);
+double GribReducedLatLonInterpretor::XResolution(
+ const GribDecoder& grib) const {
+ long res = grib.getLong("Nj");
+
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ;
+
+ longitudesSanityCheck(west, east);
+
+ return (east - west) / (2 * res);
}
+double GribReducedGaussianInterpretor::XResolution(
+ const GribDecoder& grib) const {
+ long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
-PaperPoint GribRotatedInterpretor::reference(const GribDecoder& grib, const Transformation& transformation) {
- double lon = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double lat = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- pair<double, double> xy = unrotate(lat, lon);
- UserPoint point(xy.second, xy.first);
- if (transformation.in(point))
- return transformation(point);
-
-
- int err;
- grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
-
- double value;
- /* Loop on all the lat/lon/values. */
- while (grib_iterator_next(iter, &lat, &lon, &value)) {
- pair<double, double> xy = unrotate(lat, lon);
- point = UserPoint(xy.second, xy.first);
- if (transformation.in(point)) {
- grib_iterator_delete(iter);
- return transformation(point);
- }
- }
-
- /* At the end the iterator is deleted to free memory. */
- grib_iterator_delete(iter);
- return PaperPoint(transformation.getMinPCX(), transformation.getMinPCY());
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ;
+
+ longitudesSanityCheck(west, east);
+ return (east - west) / (4 * res);
}
-pair<double, double> GribRotatedInterpretor::rotate(double lat_y,
- double lon_x) const {
- const double cToRadians = M_PI / 180.0;
- double ZRADI = 1. / cToRadians;
- double ZSYCEN = sin(cToRadians * (southPoleLat_ + 90.));
- double ZCYCEN = cos(cToRadians * (southPoleLat_ + 90.));
- double ZXMXC = cToRadians * (lon_x - southPoleLon_);
- double ZSXMXC = sin(ZXMXC);
- double ZCXMXC = cos(ZXMXC);
- double ZSYREG = sin(cToRadians * lat_y);
- double ZCYREG = cos(cToRadians * lat_y);
- double ZSYROT = ZCYCEN * ZSYREG - ZSYCEN * ZCYREG * ZCXMXC;
- ZSYROT = MAX(MIN(ZSYROT, +1.0), -1.0);
+void GribReducedGaussianInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix) const {
+ MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
+ MagLog::dev() << "GribRegularInterpretor::interpretAsMatrix" << "\n";
+
+ Timer timer("gribapi", " read grib");
+ *matrix = new Matrix();
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+ GribDecoder::InterpolateMethod interpolate = grib.interpolateMethod();
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ double missing = std::numeric_limits<double>::max();
+ grib.setDouble("missingValue", missing);
+
+ (*matrix)->missing(missing);
+ (*matrix)->akimaEnabled();
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ double plp = grib.getDouble("PLPresent");
+ long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
+ long nblat = grib.getLong("Nj");
+ longitudesSanityCheck(west, east);
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
+ << ", " << south << "]" << "\n";
+ MagLog::dev() << "PLPresent---> " << plp << "\n";
+ MagLog::dev() << "Res---> " << res << "\n";
+
+ double pl[2 * res];
+ size_t aux = 2 * res;
+ grib_get_double_array(grib.id(), "pl", pl, &aux);
+ int nblon = 0;
+ int ii = 0;
+
- double PYROT = asin(ZSYROT) * ZRADI;
+ long global = grib.getLong("global");
- double ZCYROT = cos(PYROT * cToRadians);
- double ZCXROT = (ZCYCEN * ZCYREG * ZCXMXC + ZSYCEN * ZSYREG) / ZCYROT;
- ZCXROT = MAX(MIN(ZCXROT, +1.0), -1.0);
- double ZSXROT = ZCYREG * ZSXMXC / ZCYROT;
+ // We have to determine if the field is global!
+ if (global) {
+ east = west + 360.;
+ }
+ vector<vector<double> > rows;
- double PXROT = acos(ZCXROT) * ZRADI;
+ for ( int i = 0; i < nblat; i++) {
+ // compute find first grid point ..
+ double dx = 360./pl[i];
+ rows.push_back(vector<double>());
+ for ( int n = 0; n < pl[i]; n++) {
+ double x = (n*dx );
+
+ if ( x > east) x-=360.;
+
+ if ( x >= west && x <= east) {
+ rows.back().push_back(x);
+
+ }
+ }
+ std::sort(rows.back().begin(), rows.back().end());
+
+
+ if ( rows.back().size() > nblon) nblon = rows.back().size();
+ ii += rows.back().size();
+ }
+
+
+
+
+
+
+
+
+ // compute the number of points we'll be adding to the matrix so that we can
+ // allocate them in one go, rather than allowing the STL to re-allocate
+ // when we reach the capacity
+ (*matrix)->reserve(aux * nblon);
+
+ double *data = new double[nb];
+
+ size_t aux2 = size_t(nb);
+
+ double width = east - west;
+ double step = (width) / (nblon);
+
+ grib_get_double_array(grib.id(), "values", data, &aux2);
+
+ int d = 0;
+
+ vector<double> missingLon;
+
+ for (vector<vector<double> >::iterator row = rows.begin(); row != rows.end(); ++row) {
+ vector<double> p;
+
+ for (int ii = 0; ii < row->size(); ii++) {
+ p.push_back(data[d]);
+ d++;
+ }
+ if (interpolate == GribDecoder::nearest_valid ) {
+ // Fill left vector
+ vector<double> left;
+ int last = 0;
+ int c = 0;
+ bool print = false;
+ for ( vector<double>::iterator val = p.begin(); val != p.end(); ++val) {
+ if ( *val != missing ) {
+ last = c;
+ }
+ else {
+ print = true;
+ }
+ left.push_back(last);
+ c++;
+ }
+ // Fill right vector
+ vector<double> right(p.size(), 0);
+ last = 0;
+ c = p.size()-1;
+ for ( vector<double>::reverse_iterator val = p.rbegin(); val != p.rend(); ++val) {
+ if ( *val != missing ) {
+ last = c;
+ }
+ right[c] = last;
+ c--;
+ }
+
+ int fill = grib.missingFill();
+
+ int todo = 0;
+ for (int ii = 0; ii < p.size(); ii++) {
+ double keep = p[ii];
+ if ( p[ii] == missing && todo < fill ) {
+ double lon = (*row)[ii];
+ double lon1 = (*row)[left[ii]];
+ double lon2 = (*row)[right[ii]];
+ double d1 = (lon2 - lon) / (lon2 - lon1);
+ double d2 = 1 - d1;
+ p[ii] = (d2 < 0.5) ? p[left[ii]] : p[right[ii]];
+ todo++;
+ }
+ if ( keep != missing ) {
+ todo = 0;
+ }
+ }
+
+ todo = 0;
+ for (int ii = p.size()-1; ii >= 0; ii--) {
+ double keep = p[ii];
+ if ( p[ii] == missing && todo < fill ) {
+ double lon = (*row)[ii];
+ double lon1 = (*row)[left[ii]];
+ double lon2 = (*row)[right[ii]];
+ double d1 = (lon2 - lon) / (lon2 - lon1);
+ double d2 = 1 - d1;
+ p[ii] = (d2 < 0.5) ? p[left[ii]] : p[right[ii]];
+ todo++;
+ }
+ if ( keep != missing ) {
+ todo = 0;
+ }
+
+ }
+ }
+
+
+ double lon = west;
+ unsigned int p1 = 0;
+ unsigned int p2 = 1;
+
+ vector<double>::iterator r = row->begin();
+ double lon1 = *r;
+ r++;
+ double lon2 = *r;
+
+ int x = 0;
+ while (x < nblon) {
+ if ( lon < lon1 ) {
+ (*matrix)->push_back(p[0]);
+ x++;
+ lon = west + ( x*step);
+ continue;
+ }
+ if ( lon > row->back() ) {
+ (*matrix)->push_back(p.back());
+ x++;
+ lon = west + ( x*step);
+ continue;
+ }
+ if ( lon > lon2) {
+ p1++;
+ p2++;
+ lon1 = lon2;
+ r++;
+ if ( r == row->end() )
+ r--;
+ lon2 = (*r);
+ }
+ double d1 = (lon2 - lon) / (lon2 - lon1);
+ double d2 = 1 - d1;
+ double val;
+
+
+
+
+ if (interpolate == GribDecoder::interpolate) {
+ if (p[p1] == missing )
+ val = p[p2];
+ else
+ if ( p[p2] != missing )
+ val = (p[p1] * d1) + (p[p2] * d2);
+ (*matrix)->push_back(val);
+
+ }
+ else {
+ val = (d2 < 0.5) ? p[p1] : p[p2];
+ (*matrix)->push_back(val);
+ }
+ x++;
+ lon = west + ( x*step);
+ }
+
+ }
+ delete[] data;
+
+ for (int x = 0; x < nblon; x++) {
+ (*matrix)->columnsAxis().push_back(west + (x * step));
+ }
+
+ double array[2 * res];
+ grib_get_gaussian_latitudes(res, array);
+
+ for (int i = 0; i < 2*res; i++) {
+
+ if ( same(array[i], north, 0.001) ) {
+ (*matrix)->rowsAxis().push_back(array[i]);
+ continue;
+ }
+ if ( same(array[i], south, 0.001) ) {
+ (*matrix)->rowsAxis().push_back(array[i]);
+ continue;
+ }
+ if ( array[i] < north && array[i] > south)
+ (*matrix)->rowsAxis().push_back(array[i]);
+ }
+ (*matrix)->setMapsAxis();
+}
- if (ZSXROT < 0.0)
- PXROT = -PXROT;
- return std::make_pair(PYROT, PXROT);
+void GribReducedLatLonInterpretor::print(ostream& out) const {
+ out << "GribReducedLatLonInterpretor[";
+ out << "]";
}
-void GribLambertAzimutalInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
- long im = grib.getLong("numberOfPointsAlongXAxis");
- long jm = grib.getLong("numberOfPointsAlongYAxis");
+void GribReducedGaussianInterpretor::index(GribDecoder const& grib)
+{
- RotatedMatrix *rotated = new RotatedMatrix(jm, im);
- *matrix = rotated;
+ if ( !index_.empty() )
+ return;
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ west_ = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ east_ = grib.getDouble("longitudeOfLastGridPointInDegrees");
+
+ long res = grib.getLong("numberOfParallelsBetweenAPoleAndTheEquator");
+ long nblat = grib.getLong("Nj");
+ longitudesSanityCheck(west_, east_);
+ size_t aux = 2 * res;
+ double pl[aux];
+
+
+ grib_get_double_array(grib.id(), "pl", pl, &aux);
+ double array[aux];
+
+ grib_get_gaussian_latitudes(res, array);
+
+ int index = 0;
+ bool global;
+
+ // We have to determine if the field is global!
+ if (east_ - west_ > 355.) {
+ global = true;
+ }
+
+
+ for ( int i = 0; i < nblat; i++) {
+ map<double, map<double, int> >::iterator add = index_.end();
+ if ( same(array[i], north, 0.001) )
+ index_.insert(make_pair(array[i], map<double, int>()));
+ if ( same(array[i], north, 0.001) )
+ index_.insert(make_pair(array[i], map<double, int>()));
+ if ( array[i] < north && array[i] > south)
+ index_.insert(make_pair(array[i], map<double, int>()));
+ add = index_.find(array[i]);
+ if ( add == index_.end() )
+ continue;
+
+ // compute find first grid point ..
+ double dx = 360./pl[i];
+
+ for ( int n = 0; n < pl[i]; n++) {
+ double x = (n*dx );
+
+ if ( x > east_) x-=360.;
+
+ if ( x >= west_ && x <= east_) {
+ add->second.insert(make_pair(x, index));
+ }
+ index++;
+ }
+ if (global) {
+ map<double, int>::iterator first = add->second.begin();
+ add->second.insert(make_pair(first->first+360, first->second));
+ }
+ }
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
+}
+void GribReducedLatLonInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix) const {
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ Timer timer("gribapi", " read grib");
+ *matrix = new Matrix();
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+ GribDecoder::InterpolateMethod interpolate = grib.interpolateMethod();
- double missing = -std::numeric_limits<double>::max();
+ double missing = std::numeric_limits<double>::max();
+ grib.setDouble("missingValue", missing);
- missing = grib.getDouble("missingValue");
- rotated->missing(missing);
+ (*matrix)->missing(missing);
+ (*matrix)->akimaEnabled();
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << "]" << "\n";
+ longitudesSanityCheck(west, east);
+ size_t res = grib.getLong("Nj");
- try {
- Timer time("Grib", "lambert");
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
+ << ", " << south << "]" << "\n";
+ MagLog::dev() << "Res---> " << res << "\n";
- MagLog::debug() << "Version" << grib_get_api_version() << endl;
+ double pl[res];
- vector<double>& data = rotated->values();
- vector<double>& latm = rotated->rowsArray();
- vector<double>& lonm = rotated->columnsArray();
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+ int scanning = grib.getLong("jScansPositively") ? 1 : -1;
+ double lat = scanning * grib.getDouble("jDirectionIncrementInDegrees");
- size_t aux = size_t(nb);
+ grib_get_double_array(grib.id(), "pl", pl, &res);
- grib_get_double_array(grib.id(), "latitudes", &(latm.front()), &aux);
- grib_get_double_array(grib.id(), "values", &(data.front()), &aux);
- grib_get_double_array(grib.id(), "longitudes", &(lonm.front()), &aux);
- for (int i = 0; i < nb; i++) {
+ double *data = new double[nb];
- if (lonm[i] > 180.)
- lonm[i] -= 360.;
+ size_t aux2 = size_t(nb);
- }
- /*
- vector<double> left;
- vector<double> right;
- for (int l = 0; l < jm; l++ ) {
- left.push_back(lonm[l*im]);
- right.push_back(lonm[(im-1)+(l*im)]);
+ int nblon = 0;
+ for ( int i = 0; i < res; i++)
+ if (nblon < pl[i] )
+ nblon = pl[i];
+ double width = east - west;
+ double step = width / nblon;
- }
- minlon = *min_element(left.begin(), left.end());
- maxlon = *max_element(right.begin(), right.end());
+ // We have to determine if the field is global!
+ // We have to determine if the field is global!
+ bool global = east - west > 360 - 5 * step;
- MagLog::debug() << "lat [" << minlat << ", " << maxlat << "]" << std::endl;
- MagLog::debug() << "lon [" << minlon << ", " << maxlon << "]" << std::endl;
+ if (global) {
+ east = west + 360;
+ width = east - west;
+ step = width / nblon;
+ }
+ grib_get_double_array(grib.id(), "values", data, &aux2);
+ int d = 0;
+ for (size_t i = 0; i < res; i++) {
- vector<double>& lon = (*matrix)->columnsAxis();
- for (vector<double>::iterator l = lon.begin(); l != lon.end(); ++l )
- if ( *l > 180) *l -=360;
- vector<double>& lat = (*matrix)->rowsAxis();
+ if (pl[i] == 0) {
+ // add missing data
+ for (int x = 0; x < nblon; x++)
+ (*matrix)->push_back(missing);
+ }
+ else {
- // for the lon we take the fisrt line :
- double inci = (maxlon - minlon)/((im) -1);
- double incj = (maxlat - minlat)/((jm) -1);
- for (int i = 0; i < im; i++)
- lon.push_back(minlon + (i*inci));
- // for the lon we take the fisrt column :
- for (int i = 0; i < jm; i++)
- lat.push_back(minlat + (i*incj));
+ vector<double> p;
+ vector<double> lons;
- typedef map<double, map<double, pair<int, int> > > Helper;
+ double datastep = width / pl[i];
+ for (int ii = 0; ii < pl[i]; ii++) {
+ p.push_back(data[d]);
+ lons.push_back( west + (ii*datastep) );
+ d++;
+ }
+ ASSERT( p.size() == pl[i]);
+ if ( global ) {
+ p.push_back(p.front());
+ lons.push_back( lons.back() + datastep );
- //typedef map<double, double> Helper;
- Helper helper;
- int row = 0;
- for (vector<double>::iterator y = lat.begin(); y != lat.end(); ++y) {
+ }
- helper.insert(make_pair(*y, map<double, pair<int, int> >()));
- Helper::iterator h = helper.find(*y);
+ vector<double>::iterator val = p.begin();
+ vector<double>::iterator lval = lons.begin();
+ vector<double>::iterator nval = p.begin();
+ nval++;
+ vector<double>::iterator nlval = lons.begin();
+ nlval++;
- int column = 0;
- for (vector<double>::iterator x = lon.begin(); x != lon.end(); ++x) {
- h->second.insert(make_pair(*x, std::make_pair(row, column)));
+ for (int x = 0; x < nblon; x++) {
- (*matrix)->push_back(missing);
- column++;
+ double lon = west + (x*step);
- }
- row++;
- }
+ if ( lon > *nlval ) {
+ lval++;
+ val++;
+ if ( lval == lons.end() ) {
+ val = p.begin();
+ lval = lons.begin();
- int r = 0;
- int c = 0;
+ }
+ nval++;
+ nlval++;
+ if ( nlval == lons.end() ) {
+ nval = p.begin();
+ nlval = lons.begin();
- double lat11, lat12, lat21, lat22;
- double lon11, lon12, lon21, lon22;
- double val11, val12, val21, val22;
- for (int r = 0; r < jm -1; r++) {
- for (int c = 0; c < im -1; c++) {
+ }
- lat11 = latm[c + (im*r)];
- lat12 = latm[(c+1) + (im*r)];
- minlat = std::min(lat11, lat12);
- maxlat = std::max(lat11, lat12);
- lat21 = latm[c + (im* (r+1))];
- minlat = std::min(minlat, lat21);
- maxlat = std::max(maxlat, lat21);
- lat22 = latm[(c+1) + (im* (r+1))];
- minlat = std::min(minlat, lat22);
- maxlat = std::max(maxlat, lat22);
+ }
- lon11 = lonm[c + (im*r)];
- lon12 = lonm[(c+1) + (im*r)];
- if ( lon12 < lon11 )
- lon12 +=360.;
- minlon = std::min(lon11, lon12);
- maxlon = std::max(lon11, lon12);
- lon21 = lonm[c + (im* (r+1))];
- minlon = std::min(minlon, lon21);
- maxlon = std::max(maxl inline double column(int, int column) const {
- return regular_longitudes_[column];
- }
- inline double row(int row, int) const {
- return regular_latitudes_[row];
- }on, lon21);
- lon22 = lonm[(c+1) + (im* (r+1))];
- if ( lon22 < lon21 )
- lon22 +=360.;
- minlon = std::min(minlon, lon22);
- maxlon = std::max(maxlon, lon22);
- val11 = data[c + (im*r)];
- val12 = data[(c+1) + (im*r)];
- val21 = data[c + (im* (r+1))];
- val22 = data[(c+1) + (im* (r+1))];
- // find the points from the helper!
- Helper::iterator low,up;
- low = helper.lower_bound(minlat);
- up = helper.lower_bound(maxlat);
- if ( low == helper.end() || up == helper.end() )
- break;
- for (Helper::iterator it = low; it != up; ++it) {
- if (it == helper.end()) break;
- map<double, pair<int, int> >& lons = it->second;
- map<double, pair<int, int> >::iterator llow = lons.lower_bound(minlon);
- map<double, pair<int, int> >::iterator lup = lons.lower_bound(maxlon);
- if ( llow == lons.end() || lup == lons.end() )
- break;;
- for (map<double, pair<int, int> >::iterator lit = llow; lit != lup; ++lit) {
+ double d1 = ( *nlval - lon) / (datastep);
+ if ( d1 < 0 ) d1 = 1;
+ double d2 = 1 - d1;
+ double value;
- double lat = it->first;
- double lon = lit->first;
- std::pair<int, int> index = lit->second;
+ if (interpolate == GribDecoder::interpolate) {
+ if (*val == missing || *nval == missing)
+ value = missing;
+ else
+ value = (d1 * (*val)) + (d2 * (*nval));
+ }
+ else {
+ value = (d2 < 0.5) ? *val : *nval;
+ }
+ (*matrix)->push_back(value);
+ }
- // we interpolate at the point using the 4 points found!
- double val = missing;
- map<double, double> values;
- vector<double> distances;
- distances.push_back((lon12 - lon)*(lon12 - lon) + (lat12 -lat) *(lat12 -lat));
- values[distances.back()] = val12;
- distances.push_back((lon11 - lon)*(lon11 - lon) + (lat11 -lat) *(lat11 -lat));
- values[distances.back()] = val11;
- distances.push_back((lon21 - lon)*(lon21 - lon) + (lat21 -lat) *(lat21 -lat));
- values[distances.back()] = val21;
- distances.push_back((lon22 - lon)*(lon22 - lon) + (lat22 -lat) *(lat22 -lat));
- values[distances.back()] = val22;
- if ( (**matrix)[index.second +( index.first*im)] == missing )
- (**matrix)[index.second +( index.first*im)] = values[*std::min_element(distances.begin(), distances.end())];
- //we compute the distance ... we take the vlaue of the nearest non_missing point!
- }
+ }
+ }
+ delete[] data;
- }
+ for (int x = 0; x < nblon; x++) {
+ (*matrix)->columnsAxis().push_back(west + (x * step));
+ }
- }
+ double y = north;
+ for (long i = 0; i < nblat; i++) {
+ (*matrix)->rowsAxis().push_back(y);
+ y += lat;
+ }
+ (*matrix)->setMapsAxis();
+}
- (*matrix)->setMapsAxis();
- (*matrix)->missing(missing);
- }
+/*
+ * Imported from Metview MvGrid...
+ */
+
+void GribRotatedInterpretor::print(ostream& out) const {
+ out << "GribRotatedInterpretor[]";
+}
+
+UserPoint GribLambertAzimutalInterpretor::unrotate(double lat,
+ double lon) const {
+
+ return UserPoint(lon, lat);
+}
+
+double GribLambertAzimutalInterpretor::XResolution(const GribDecoder& grib) const
+{
+ return 0.0125;
+}
+pair<double, double> GribRotatedInterpretor::unrotate(double lat_y,
+ double lon_x) const {
+ const double cToRadians = M_PI / 180.0;
+ double ZRADI = 1. / cToRadians;
+ double ZSYCEN = sin(cToRadians * (southPoleLat_ + 90.));
+ double ZCYCEN = cos(cToRadians * (southPoleLat_ + 90.));
+ double ZSXROT = sin(cToRadians * lon_x);
+ double ZCXROT = cos(cToRadians * lon_x);
+ double ZSYROT = sin(cToRadians * lat_y);
+ double ZCYROT = cos(cToRadians * lat_y);
+ double ZSYREG = ZCYCEN * ZSYROT + ZSYCEN * ZCYROT * ZCXROT;
+ ZSYREG = MAX(MIN(ZSYREG, +1.0), -1.0);
+ double PYREG = asin(ZSYREG) * ZRADI;
+ double ZCYREG = cos(PYREG * cToRadians);
+ double ZCXMXC = (ZCYCEN * ZCYROT * ZCXROT - ZSYCEN * ZSYROT) / ZCYREG;
+ ZCXMXC = MAX(MIN(ZCXMXC, +1.0), -1.0);
+ double ZSXMXC = ZCYROT * ZSXROT / ZCYREG;
+ double ZXMXC = acos(ZCXMXC) * ZRADI;
+ if (ZSXMXC < 0.0)
+ ZXMXC = -ZXMXC;
+ double PXREG = ZXMXC + southPoleLon_;
+ return std::make_pair(PYREG, PXREG);
+}
+PaperPoint GribRotatedInterpretor::reference(const GribDecoder& grib, const Transformation& transformation) {
+ double lon = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double lat = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ pair<double, double> xy = unrotate(lat, lon);
+ UserPoint point(xy.second, xy.first);
+ if (transformation.in(point))
+ return transformation(point);
+
+
+ int err;
+ grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
+
+ double value;
+ /* Loop on all the lat/lon/values. */
+ while (grib_iterator_next(iter, &lat, &lon, &value)) {
+ pair<double, double> xy = unrotate(lat, lon);
+ point = UserPoint(xy.second, xy.first);
+ if (transformation.in(point)) {
+ grib_iterator_delete(iter);
+ return transformation(point);
+ }
+ }
+
+ /* At the end the iterator is deleted to free memory. */
+ grib_iterator_delete(iter);
+ return PaperPoint(transformation.getMinPCX(), transformation.getMinPCY());
+}
+pair<double, double> GribRotatedInterpretor::rotate(double lat_y,
+ double lon_x) const {
+ const double cToRadians = M_PI / 180.0;
+ double ZRADI = 1. / cToRadians;
+ double ZSYCEN = sin(cToRadians * (southPoleLat_ + 90.));
+ double ZCYCEN = cos(cToRadians * (southPoleLat_ + 90.));
+ double ZXMXC = cToRadians * (lon_x - southPoleLon_);
+ double ZSXMXC = sin(ZXMXC);
+ double ZCXMXC = cos(ZXMXC);
+ double ZSYREG = sin(cToRadians * lat_y);
+ double ZCYREG = cos(cToRadians * lat_y);
+ double ZSYROT = ZCYCEN * ZSYREG - ZSYCEN * ZCYREG * ZCXMXC;
+ ZSYROT = MAX(MIN(ZSYROT, +1.0), -1.0);
+ double PYROT = asin(ZSYROT) * ZRADI;
- MagLog::dev() << **matrix << "\n";
+ double ZCYROT = cos(PYROT * cToRadians);
+ double ZCXROT = (ZCYCEN * ZCYREG * ZCXMXC + ZSYCEN * ZSYREG) / ZCYROT;
+ ZCXROT = MAX(MIN(ZCXROT, +1.0), -1.0);
+ double ZSXROT = ZCYREG * ZSXMXC / ZCYROT;
+ double PXROT = acos(ZCXROT) * ZRADI;
- */
- } catch (MagicsException& e) {
- MagLog::error() << e << "\n";
- }
+ if (ZSXROT < 0.0)
+ PXROT = -PXROT;
+
+ return std::make_pair(PYROT, PXROT);
+}
+
+void GribLambertAzimutalInterpretor::interpretAsMatrix(const GribDecoder& grib,
+ Matrix** matrix) const {
+ long im = grib.getLong("numberOfPointsAlongXAxis");
+ long jm = grib.getLong("numberOfPointsAlongYAxis");
+
+ RotatedMatrix *rotated = new RotatedMatrix(jm, im);
+ *matrix = rotated;
+
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+
+ double missing = -std::numeric_limits<double>::max();
+
+ missing = grib.getDouble("missingValue");
+ rotated->missing(missing);
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << "]" << "\n";
+
+ try {
+ Timer time("Grib", "lambert");
+
+ MagLog::debug() << "Version" << grib_get_api_version() << endl;
+
+ vector<double>& data = rotated->values();
+ vector<double>& latm = rotated->rowsArray();
+ vector<double>& lonm = rotated->columnsArray();
+
+ size_t aux = size_t(nb);
+
+ grib_get_double_array(grib.id(), "latitudes", &(latm.front()), &aux);
+ grib_get_double_array(grib.id(), "values", &(data.front()), &aux);
+ grib_get_double_array(grib.id(), "longitudes", &(lonm.front()), &aux);
+ for (int i = 0; i < nb; i++) {
+
+ if (lonm[i] > 180.)
+ lonm[i] -= 360.;
+
+ }
+
+ } catch (MagicsException& e) {
+ MagLog::error() << e << "\n";
+ }
}
void GribLambertAzimutalInterpretor::print(ostream& out) const {
- out << "GribLambertAzimutalInterpretor[]";
+ out << "GribLambertAzimutalInterpretor[]";
}
void GribRotatedInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
-
- southPoleLat_ = grib.getDouble("latitudeOfSouthernPoleInDegrees");
- southPoleLon_ = grib.getDouble("longitudeOfSouthernPoleInDegrees");
- angle_ = grib.getDouble("angleOfRotationInDegrees") * 180.0 / M_PI;
- uvRelativeToGrid_ = grib.getLong("uvRelativeToGrid");
- if (original_) {
- long nblon = grib.getLong("numberOfPointsAlongAParallel");
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
-
- *matrix = new RotatedMatrix(nblat, nblon);
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
-
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
- double missing = -std::numeric_limits<double>::max();
- grib.setDouble("missingValue", missing);
+ Matrix** matrix) const {
+
+ southPoleLat_ = grib.getDouble("latitudeOfSouthernPoleInDegrees");
+ southPoleLon_ = grib.getDouble("longitudeOfSouthernPoleInDegrees");
+ angle_ = grib.getDouble("angleOfRotationInDegrees") * 180.0 / M_PI;
+ uvRelativeToGrid_ = grib.getLong("uvRelativeToGrid");
+ if (original_) {
+ long nblon = grib.getLong("numberOfPointsAlongAParallel");
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+
+ *matrix = new RotatedMatrix(nblat, nblon);
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ double missing = -std::numeric_limits<double>::max();
+ grib.setDouble("missingValue", missing);
- (*matrix)->missing(missing);
-
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
- ;
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- ;
- longitudesSanityCheck(west, east);
-
- double lon = (east - west) / (nblon - 1);
- double lat = (south - north) / (nblat - 1);
-
- vector<double>& rows =
- static_cast<RotatedMatrix*>(*matrix)->rowsArray();
- vector<double>& columns =
- static_cast<RotatedMatrix*>(*matrix)->columnsArray();
- vector<double>& values = static_cast<RotatedMatrix*>(*matrix)->values();
- MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
- << west + (nblon - 1) * lon << ")" << endl;
-
- double y = north;
- for (int i = 0; i < nblat; i++) {
- double x = west;
- for (int j = 0; j < nblon; j++) {
- if (i == 0)
- (*matrix)->columnsAxis().push_back(x);
- std::pair<double, double> point = unrotate(y, x);
- columns.push_back(point.second);
- rows.push_back(point.first);
- x = west + (j + 1) * lon;
-
- }
-
- y = north + (i + 1) * lat;
-
- }
-
- try {
- (*matrix)->resize(nb);
- size_t aux = size_t(nb);
- grib_get_double_array(grib.id(), "values", &values.front(), &aux);
- } catch (...) {
- throw MagicsException("Not enough memory");
- }
-
- return;
- }
-
- long nblon = grib.getLong("numberOfPointsAlongAParallel");
- long nblat = grib.getLong("numberOfPointsAlongAMeridian");
- *matrix = new Matrix(nblat, nblon);
-
- Matrix* helper = new Matrix(nblat, nblon); // settup as the equivalent regular matrix!
-
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
-
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
- double missing = -std::numeric_limits<double>::max();
- grib.setDouble("missingValue", missing);
- helper->missing(missing);
- (*matrix)->missing(missing);
-
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
- double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
- ;
- double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
- ;
- longitudesSanityCheck(west, east);
-
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
- << ", " << south << "]" << "\n";
-
- double lon = (east - west) / (nblon - 1);
- double lat = (south - north) / (nblat - 1);
-
- MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
- << west + (nblon - 1) * lon << ")" << endl;
-
- double y = north;
- for (int i = 0; i < nblat; i++) {
-
- helper->rowsAxis().push_back(y);
- y = north + (i + 1) * lat;
-
- }
-
- double x = west;
- for (int i = 0; i < nblon; i++) {
-
- helper->columnsAxis().push_back(x);
- x = west + (i + 1) * lon;
-
- }
-
- helper->setMapsAxis();
-
- try {
- helper->resize(nb);
- size_t aux = size_t(nb);
- grib_get_double_array(grib.id(), "values", &helper->front(), &aux);
- } catch (...) {
- throw MagicsException("Not enough memory");
- }
-
- lon = west;
- lat = north;
- double steplon = (east - west) / (nblon - 1);
- double steplat = (south - north) / (nblat - 1);
-
- // Fisrt try to find the bounding box
- vector<double> rows;
- rows.reserve(nb);
- vector<double> columns;
- columns.reserve(nb);
- vector<double> values;
- values.reserve(nb);
-
- for (int j = 0; j < nblat; j++) {
- lon = west;
-
- for (int i = 0; i < nblon; i++) {
- std::pair<double, double> point = unrotate(lat, lon);
-
- rows.push_back(point.first);
- columns.push_back(point.second);
-
- lon += steplon;
- }
- lat += steplat;
- }
-
- double minx = *std::min_element(columns.begin(), columns.end());
- double maxx = *std::max_element(columns.begin(), columns.end());
- double miny = *std::min_element(rows.begin(), rows.end());
- double maxy = *std::max_element(rows.begin(), rows.end());
-
- double stepx = (maxx - minx) / (nblon - 1);
- double stepy = (maxy - miny) / (nblat - 1);
- x = minx;
- y = miny;
- // Create the Axis for Regular Matrix..
- for (int i = 0; i < nblon; i++) {
- (*matrix)->columnsAxis().push_back(x);
- x += stepx;
- }
- for (int j = 0; j < nblat; j++) {
- (*matrix)->rowsAxis().push_back(y);
- y += stepy;
- }
-
- miny = std::min(north, south);
- maxy = std::max(north, south);
- minx = std::min(west, east);
- maxx = std::max(west, east);
-
- (*matrix)->setMapsAxis();
- for (int j = 0; j < nblat; j++) {
- for (int i = 0; i < nblon; i++) {
-
- pair<double, double> point = rotate((*matrix)->row(j, i),
- (*matrix)->column(j, i));
- if (point.first > miny && point.first < maxy && point.second > minx
- && point.second < maxx) {
- (*matrix)->push_back(
- helper->interpolate(point.first, point.second));
-
- } else {
- (*matrix)->push_back(missing);
-
- }
- }
- }
+ (*matrix)->missing(missing);
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ ;
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ;
+ longitudesSanityCheck(west, east);
+
+ double lon = (east - west) / (nblon - 1);
+ double lat = (south - north) / (nblat - 1);
+
+ vector<double>& rows =
+ static_cast<RotatedMatrix*>(*matrix)->rowsArray();
+ vector<double>& columns =
+ static_cast<RotatedMatrix*>(*matrix)->columnsArray();
+ vector<double>& values = static_cast<RotatedMatrix*>(*matrix)->values();
+ MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
+ << west + (nblon - 1) * lon << ")" << endl;
+
+ double y = north;
+ for (int i = 0; i < nblat; i++) {
+ double x = west;
+ for (int j = 0; j < nblon; j++) {
+ if (i == 0)
+ (*matrix)->columnsAxis().push_back(x);
+ std::pair<double, double> point = unrotate(y, x);
+ columns.push_back(point.second);
+ rows.push_back(point.first);
+ x = west + (j + 1) * lon;
+
+ }
+
+ y = north + (i + 1) * lat;
+
+ }
+
+ try {
+ (*matrix)->resize(nb);
+ size_t aux = size_t(nb);
+ grib_get_double_array(grib.id(), "values", &values.front(), &aux);
+ } catch (...) {
+ throw MagicsException("Not enough memory");
+ }
+
+ return;
+ }
+
+ long nblon = grib.getLong("numberOfPointsAlongAParallel");
+ long nblat = grib.getLong("numberOfPointsAlongAMeridian");
+ *matrix = new Matrix(nblat, nblon);
+
+ Matrix* helper = new Matrix(nblat, nblon); // settup as the equivalent regular matrix!
+
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ double missing = -std::numeric_limits<double>::max();
+ grib.setDouble("missingValue", missing);
+ helper->missing(missing);
+ (*matrix)->missing(missing);
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ double south = grib.getDouble("latitudeOfLastGridPointInDegrees");
+ ;
+ double east = grib.getDouble("longitudeOfLastGridPointInDegrees");
+ ;
+ longitudesSanityCheck(west, east);
+
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << ", " << east
+ << ", " << south << "]" << "\n";
+
+ double lon = (east - west) / (nblon - 1);
+ double lat = (south - north) / (nblat - 1);
+
+ MagLog::dev() << "calcul -->" << lon << " (from->" << west << " to-->"
+ << west + (nblon - 1) * lon << ")" << endl;
+
+ double y = north;
+ for (int i = 0; i < nblat; i++) {
+
+ helper->rowsAxis().push_back(y);
+ y = north + (i + 1) * lat;
+
+ }
+
+ double x = west;
+ for (int i = 0; i < nblon; i++) {
+
+ helper->columnsAxis().push_back(x);
+ x = west + (i + 1) * lon;
+
+ }
+
+ helper->setMapsAxis();
+
+ try {
+ helper->resize(nb);
+ size_t aux = size_t(nb);
+ grib_get_double_array(grib.id(), "values", &helper->front(), &aux);
+ } catch (...) {
+ throw MagicsException("Not enough memory");
+ }
+
+ lon = west;
+ lat = north;
+ double steplon = (east - west) / (nblon - 1);
+ double steplat = (south - north) / (nblat - 1);
+
+ // Fisrt try to find the bounding box
+ vector<double> rows;
+ rows.reserve(nb);
+ vector<double> columns;
+ columns.reserve(nb);
+ vector<double> values;
+ values.reserve(nb);
+
+ for (int j = 0; j < nblat; j++) {
+ lon = west;
+
+ for (int i = 0; i < nblon; i++) {
+ std::pair<double, double> point = unrotate(lat, lon);
+
+ rows.push_back(point.first);
+ columns.push_back(point.second);
+
+ lon += steplon;
+ }
+ lat += steplat;
+ }
+
+ double minx = *std::min_element(columns.begin(), columns.end());
+ double maxx = *std::max_element(columns.begin(), columns.end());
+ double miny = *std::min_element(rows.begin(), rows.end());
+ double maxy = *std::max_element(rows.begin(), rows.end());
+
+ double stepx = (maxx - minx) / (nblon - 1);
+ double stepy = (maxy - miny) / (nblat - 1);
+ x = minx;
+ y = miny;
+ // Create the Axis for Regular Matrix..
+ for (int i = 0; i < nblon; i++) {
+ (*matrix)->columnsAxis().push_back(x);
+ x += stepx;
+ }
+ for (int j = 0; j < nblat; j++) {
+ (*matrix)->rowsAxis().push_back(y);
+ y += stepy;
+ }
+
+ miny = std::min(north, south);
+ maxy = std::max(north, south);
+ minx = std::min(west, east);
+ maxx = std::max(west, east);
+
+ (*matrix)->setMapsAxis();
+ for (int j = 0; j < nblat; j++) {
+ for (int i = 0; i < nblon; i++) {
+
+ pair<double, double> point = rotate((*matrix)->row(j, i),
+ (*matrix)->column(j, i));
+ if (point.first > miny && point.first < maxy && point.second > minx
+ && point.second < maxx) {
+ (*matrix)->push_back(
+ helper->interpolate(point.first, point.second));
+
+ } else {
+ (*matrix)->push_back(missing);
+
+ }
+ }
+ }
}
void GribRotatedInterpretor::interpret2D(double& lat, double& lon, double& uc,
- double& vc) const {
- if (!uvRelativeToGrid_)
- return;
- double speed = sqrt((uc * uc) + (vc * vc));
- double angle = atan2(vc, uc);
+ double& vc) const {
+ if (!uvRelativeToGrid_)
+ return;
+ double speed = sqrt((uc * uc) + (vc * vc));
+ double angle = atan2(vc, uc);
- std::pair<double, double> pt = rotate(lat, lon);
- std::pair<double, double> pv = unrotate(pt.first, pt.second + 1);
+ std::pair<double, double> pt = rotate(lat, lon);
+ std::pair<double, double> pv = unrotate(pt.first, pt.second + 1);
- double rangle = atan2(pv.first - lat, pv.second - lon) + angle;
- //components.second *= f;
- // we the angle and the spped we compute u/v...
- uc = speed * cos(rangle);
- vc = speed * sin(rangle);
+ double rangle = atan2(pv.first - lat, pv.second - lon) + angle;
+ //components.second *= f;
+ // we the angle and the spped we compute u/v...
+ uc = speed * cos(rangle);
+ vc = speed * sin(rangle);
}
void GribRotatedInterpretor::raw(const GribDecoder& grib,
- const Transformation& transformation, const string& key,
- map<double, map<double, CustomisedPoint*> >& points) const {
- double factor, offset;
- scaling(grib, factor, offset);
- int err;
- southPoleLat_ = grib.getDouble("latitudeOfSouthernPoleInDegrees");
- southPoleLon_ = grib.getDouble("longitudeOfSouthernPoleInDegrees");
- angle_ = grib.getDouble("angleOfRotationInDegrees") * 180.0 / M_PI;
- ;
- grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
- double missing = grib.getDouble("missingValue");
-
- double lat, lon, value;
- /* Loop on all the lat/lon/values. */
- while (grib_iterator_next(iter, &lat, &lon, &value)) {
-
- pair<double, double> coords = unrotate(lat, lon);
- lat = coords.first;
- lon = coords.second;
- if (value != missing) {
- /*
- std::stack<UserPoint> duplicates;
- UserPoint geo(lon, lat);
- value = (value*factor)+offset;
- transformation.populate(lon, lat, value, points);
- */
-
- }
-
- }
-
- /* At the end the iterator is deleted to free memory. */
- grib_iterator_delete(iter);
+ const Transformation& transformation, const string& key,
+ map<double, map<double, CustomisedPoint*> >& points) const {
+ double factor, offset;
+ scaling(grib, factor, offset);
+ int err;
+ southPoleLat_ = grib.getDouble("latitudeOfSouthernPoleInDegrees");
+ southPoleLon_ = grib.getDouble("longitudeOfSouthernPoleInDegrees");
+ angle_ = grib.getDouble("angleOfRotationInDegrees") * 180.0 / M_PI;
+ ;
+ grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
+ double missing = grib.getDouble("missingValue");
+
+ double lat, lon, value;
+ /* Loop on all the lat/lon/values. */
+ while (grib_iterator_next(iter, &lat, &lon, &value)) {
+
+ pair<double, double> coords = unrotate(lat, lon);
+ lat = coords.first;
+ lon = coords.second;
+ if (value != missing) {
+ /*
+ std::stack<UserPoint> duplicates;
+ UserPoint geo(lon, lat);
+ value = (value*factor)+offset;
+ transformation.populate(lon, lat, value, points);
+ */
+
+ }
+
+ }
+
+ /* At the end the iterator is deleted to free memory. */
+ grib_iterator_delete(iter);
}
void GribLambertInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
- long im = grib.getLong("numberOfPointsAlongXAxis");
- long jm = grib.getLong("numberOfPointsAlongYAxis");
+ Matrix** matrix) const {
+ long im = grib.getLong("numberOfPointsAlongXAxis");
+ long jm = grib.getLong("numberOfPointsAlongYAxis");
+
+ *matrix = new Matrix(im, jm);
+
+ size_t nb;
+ grib_get_size(grib.id(), "values", &nb);
+
+ MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
+ double missing = -std::numeric_limits<double>::max();
+ missing = grib.getDouble("missingValue");
+
+ double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
+ double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+
+ MagLog::dev() << "NewAPI---> area[" << west << ", " << north << "]" << "\n";
- *matrix = new Matrix(im, jm);
+ try {
+ Timer time("Grib", "lambert");
- size_t nb;
- grib_get_size(grib.id(), "values", &nb);
+ MagLog::debug() << "Version" << grib_get_api_version() << endl;
- MagLog::dev() << "numberOfFieldValues[" << nb << "]" << "\n";
- double missing = -std::numeric_limits<double>::max();
- missing = grib.getDouble("missingValue");
+ vector<double> latm;
+ vector<double> lonm;
+ vector<double> data;
+ latm.reserve(nb);
+ lonm.reserve(nb);
+ data.reserve(nb);
- double north = grib.getDouble("latitudeOfFirstGridPointInDegrees");
- double west = grib.getDouble("longitudeOfFirstGridPointInDegrees");
+ size_t aux = size_t(nb);
- MagLog::dev() << "NewAPI---> area[" << west << ", " << north << "]" << "\n";
+ grib_get_double_array(grib.id(), "latitudes", &(latm.front()), &aux);
- try {
- Timer time("Grib", "lambert");
+ double minlat = *min_element(latm.begin(), latm.end());
+ double maxlat = *max_element(latm.begin(), latm.end());
+ ;
+ grib_get_double_array(grib.id(), "longitudes", &(lonm.front()), &aux);
- MagLog::debug() << "Version" << grib_get_api_version() << endl;
+ double minlon = *min_element(lonm.begin(), lonm.end());
+ double maxlon = *max_element(lonm.begin(), lonm.end());
+ ;
- vector<double> latm;
- vector<double> lonm;
- vector<double> data;
- latm.reserve(nb);
- lonm.reserve(nb);
- data.reserve(nb);
+ // This test needs to be improved ...
- size_t aux = size_t(nb);
+ if (minlon > 50.)
+ minlon -= 360;
+ if (maxlon > 50.)
+ maxlon -= 360;
- grib_get_double_array(grib.id(), "latitudes", &(latm.front()), &aux);
+ grib_get_double_array(grib.id(), "values", &(data.front()), &aux);
- double minlat = *min_element(latm.begin(), latm.end());
- double maxlat = *max_element(latm.begin(), latm.end());
- ;
- grib_get_double_array(grib.id(), "longitudes", &(lonm.front()), &aux);
-
- double minlon = *min_element(lonm.begin(), lonm.end());
- double maxlon = *max_element(lonm.begin(), lonm.end());
- ;
-
- // This test needs to be improved ...
-
- if (minlon > 50.)
- minlon -= 360;
- if (maxlon > 50.)
- maxlon -= 360;
-
- grib_get_double_array(grib.id(), "values", &(data.front()), &aux);
- double min = *min_element(data.begin(), data.end());
- double max = *max_element(data.begin(), data.end());
- ;
-
- for (int i = 0; i < nb; i++) {
- if (lonm[i] > 50.)
- lonm[i] = lonm[i] - 360;
-
- if (minlat > latm[i])
- minlat = latm[i];
- if (maxlat < latm[i])
- maxlat = latm[i];
- if (minlon > lonm[i])
- minlon = lonm[i];
- if (maxlon < lonm[i])
- maxlon = lonm[i];
- }
-
- MagLog::debug() << "lat [" << minlat << ", " << maxlat << "]"
- << std::endl;
- MagLog::debug() << "lon [" << minlon << ", " << maxlon << "]"
- << std::endl;
-
- vector<double>& lon = (*matrix)->columnsAxis();
- vector<double>& lat = (*matrix)->rowsAxis();
-
- // for the lon we take the fisrt line :
- double inci = (maxlon - minlon) / ((im) - 1);
- double incj = (maxlat - minlat) / ((jm) - 1);
- for (int i = 0; i < im; i++)
- lon.push_back(minlon + (i * inci));
- // for the lon we take the fisrt column :
- for (int i = 0; i < jm; i++)
- lat.push_back(minlat + (i * incj));
-
- typedef map<double, map<double, pair<int, int> > > Helper;
-
- //typedef map<double, double> Helper;
- Helper helper;
- int row = 0;
- for (vector<double>::iterator y = lat.begin(); y != lat.end(); ++y) {
-
- helper.insert(make_pair(*y, map<double, pair<int, int> >()));
-
- Helper::iterator h = helper.find(*y);
-
- int column = 0;
- for (vector<double>::iterator x = lon.begin(); x != lon.end();
- ++x) {
- h->second.insert(make_pair(*x, std::make_pair(row, column)));
-
- (*matrix)->push_back(missing);
- column++;
-
- }
- row++;
- }
-
- int r = 0;
- int c = 0;
-
- double lat11, lat12, lat21, lat22;
- double lon11, lon12, lon21, lon22;
- double val11, val12, val21, val22;
-
- for (int r = 0; r < jm - 1; r++) {
- for (int c = 0; c < im - 1; c++) {
-
- lat11 = latm[c + (im * r)];
-
- lat12 = latm[(c + 1) + (im * r)];
- minlat = std::min(lat11, lat12);
- maxlat = std::max(lat11, lat12);
- lat21 = latm[c + (im * (r + 1))];
- minlat = std::min(minlat, lat21);
- maxlat = std::max(maxlat, lat21);
- lat22 = latm[(c + 1) + (im * (r + 1))];
- minlat = std::min(minlat, lat22);
- maxlat = std::max(maxlat, lat22);
-
- lon11 = lonm[c + (im * r)];
- lon12 = lonm[(c + 1) + (im * r)];
- if (lon12 < lon11)
- lon12 += 360.;
- minlon = std::min(lon11, lon12);
- maxlon = std::max(lon11, lon12);
- lon21 = lonm[c + (im * (r + 1))];
- minlon = std::min(minlon, lon21);
- maxlon = std::max(maxlon, lon21);
- lon22 = lonm[(c + 1) + (im * (r + 1))];
- if (lon22 < lon21)
- lon22 += 360.;
- minlon = std::min(minlon, lon22);
- maxlon = std::max(maxlon, lon22);
-
- val11 = data[c + (im * r)];
- val12 = data[(c + 1) + (im * r)];
- val21 = data[c + (im * (r + 1))];
- val22 = data[(c + 1) + (im * (r + 1))];
-
- // find the points from the helper!
- Helper::iterator low, up;
- low = helper.lower_bound(minlat);
- up = helper.lower_bound(maxlat);
- if (low == helper.end() || up == helper.end())
- break;
- for (Helper::iterator it = low; it != up; ++it) {
- if (it == helper.end())
- break;
- map<double, pair<int, int> >& lons = it->second;
- map<double, pair<int, int> >::iterator llow =
- lons.lower_bound(minlon);
- map<double, pair<int, int> >::iterator lup =
- lons.lower_bound(maxlon);
- if (llow == lons.end() || lup == lons.end())
- break;;
- for (map<double, pair<int, int> >::iterator lit = llow;
- lit != lup; ++lit) {
-
- double lat = it->first;
- double lon = lit->first;
- std::pair<int, int> index = lit->second;
-
- // we interpolate at the point using the 4 points found!
- double val = missing;
- if (val11 != missing && val12 != missing
- && val21 != missing && val22 != missing) {
- double val1 = ((lon12 - lon) / (lon12 - lon11))
- * val11
- + ((lon - lon11) / (lon12 - lon11)) * val12;
-
- double val2 = ((lon22 - lon) / (lon22 - lon21))
- * val21
- + ((lon - lon21) / (lon22 - lon21)) * val22;
- if (isnan(val1)) {
- if (isnan(val2)) {
- val = missing;
- } else
- val = ((lat - lat11) / (lat22 - lat11))
- * val2;
- } else {
- if (isnan(val2)) {
- val = ((lat22 - lat) / (lat22 - lat11))
- * val1;
- } else {
- val = ((lat22 - lat) / (lat22 - lat11))
- * val1
- + ((lat - lat11) / (lat22 - lat11))
- * val2;
- }
- }
-
- if (isnan(val) || isinf(val) || isinf(-val)) {
- val = missing;
- }
- }
- if (isnan(val))
- val = missing;
- if ((**matrix)[index.second + (index.first * im)]
- == missing) {
- (**matrix)[index.second + (index.first * im)] = val;
-
- }
-
- }
-
- }
-
- }
-
- (*matrix)->setMapsAxis();
- (*matrix)->missing(missing);
- }
-
- MagLog::dev() << **matrix << "\n";
-
- }
-
- catch (MagicsException& e) {
- MagLog::error() << e << "\n";
- }
+
+
+ for (int i = 0; i < nb; i++) {
+ if (lonm[i] > 50.)
+ lonm[i] = lonm[i] - 360;
+
+ if (minlat > latm[i])
+ minlat = latm[i];
+ if (maxlat < latm[i])
+ maxlat = latm[i];
+ if (minlon > lonm[i])
+ minlon = lonm[i];
+ if (maxlon < lonm[i])
+ maxlon = lonm[i];
+ }
+
+ MagLog::debug() << "lat [" << minlat << ", " << maxlat << "]"
+ << std::endl;
+ MagLog::debug() << "lon [" << minlon << ", " << maxlon << "]"
+ << std::endl;
+
+ vector<double>& lon = (*matrix)->columnsAxis();
+ vector<double>& lat = (*matrix)->rowsAxis();
+
+ // for the lon we take the fisrt line :
+ double inci = (maxlon - minlon) / ((im) - 1);
+ double incj = (maxlat - minlat) / ((jm) - 1);
+ for (int i = 0; i < im; i++)
+ lon.push_back(minlon + (i * inci));
+ // for the lon we take the fisrt column :
+ for (int i = 0; i < jm; i++)
+ lat.push_back(minlat + (i * incj));
+
+ typedef map<double, map<double, pair<int, int> > > Helper;
+
+ //typedef map<double, double> Helper;
+ Helper helper;
+ int row = 0;
+ for (vector<double>::iterator y = lat.begin(); y != lat.end(); ++y) {
+
+ helper.insert(make_pair(*y, map<double, pair<int, int> >()));
+
+ Helper::iterator h = helper.find(*y);
+
+ int column = 0;
+ for (vector<double>::iterator x = lon.begin(); x != lon.end();
+ ++x) {
+ h->second.insert(make_pair(*x, std::make_pair(row, column)));
+
+ (*matrix)->push_back(missing);
+ column++;
+
+ }
+ row++;
+ }
+
+
+
+ double lat11, lat12, lat21, lat22;
+ double lon11, lon12, lon21, lon22;
+ double val11, val12, val21, val22;
+
+ for (int r = 0; r < jm - 1; r++) {
+ for (int c = 0; c < im - 1; c++) {
+
+ lat11 = latm[c + (im * r)];
+
+ lat12 = latm[(c + 1) + (im * r)];
+ minlat = std::min(lat11, lat12);
+ maxlat = std::max(lat11, lat12);
+ lat21 = latm[c + (im * (r + 1))];
+ minlat = std::min(minlat, lat21);
+ maxlat = std::max(maxlat, lat21);
+ lat22 = latm[(c + 1) + (im * (r + 1))];
+ minlat = std::min(minlat, lat22);
+ maxlat = std::max(maxlat, lat22);
+
+ lon11 = lonm[c + (im * r)];
+ lon12 = lonm[(c + 1) + (im * r)];
+ if (lon12 < lon11)
+ lon12 += 360.;
+ minlon = std::min(lon11, lon12);
+ maxlon = std::max(lon11, lon12);
+ lon21 = lonm[c + (im * (r + 1))];
+ minlon = std::min(minlon, lon21);
+ maxlon = std::max(maxlon, lon21);
+ lon22 = lonm[(c + 1) + (im * (r + 1))];
+ if (lon22 < lon21)
+ lon22 += 360.;
+ minlon = std::min(minlon, lon22);
+ maxlon = std::max(maxlon, lon22);
+
+ val11 = data[c + (im * r)];
+ val12 = data[(c + 1) + (im * r)];
+ val21 = data[c + (im * (r + 1))];
+ val22 = data[(c + 1) + (im * (r + 1))];
+
+ // find the points from the helper!
+ Helper::iterator low, up;
+ low = helper.lower_bound(minlat);
+ up = helper.lower_bound(maxlat);
+ if (low == helper.end() || up == helper.end())
+ break;
+ for (Helper::iterator it = low; it != up; ++it) {
+ if (it == helper.end())
+ break;
+ map<double, pair<int, int> >& lons = it->second;
+ map<double, pair<int, int> >::iterator llow =
+ lons.lower_bound(minlon);
+ map<double, pair<int, int> >::iterator lup =
+ lons.lower_bound(maxlon);
+ if (llow == lons.end() || lup == lons.end())
+ break;;
+ for (map<double, pair<int, int> >::iterator lit = llow;
+ lit != lup; ++lit) {
+
+ double lat = it->first;
+ double lon = lit->first;
+ std::pair<int, int> index = lit->second;
+
+ // we interpolate at the point using the 4 points found!
+ double val = missing;
+ if (val11 != missing && val12 != missing
+ && val21 != missing && val22 != missing) {
+ double val1 = ((lon12 - lon) / (lon12 - lon11))
+ * val11
+ + ((lon - lon11) / (lon12 - lon11)) * val12;
+
+ double val2 = ((lon22 - lon) / (lon22 - lon21))
+ * val21
+ + ((lon - lon21) / (lon22 - lon21)) * val22;
+ if (isnan(val1)) {
+ if (isnan(val2)) {
+ val = missing;
+ } else
+ val = ((lat - lat11) / (lat22 - lat11))
+ * val2;
+ } else {
+ if (isnan(val2)) {
+ val = ((lat22 - lat) / (lat22 - lat11))
+ * val1;
+ } else {
+ val = ((lat22 - lat) / (lat22 - lat11))
+ * val1
+ + ((lat - lat11) / (lat22 - lat11))
+ * val2;
+ }
+ }
+
+ if (isnan(val) || isinf(val) || isinf(-val)) {
+ val = missing;
+ }
+ }
+ if (isnan(val))
+ val = missing;
+ if ((**matrix)[index.second + (index.first * im)]
+ == missing) {
+ (**matrix)[index.second + (index.first * im)] = val;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ (*matrix)->setMapsAxis();
+ (*matrix)->missing(missing);
+ }
+
+ MagLog::dev() << **matrix << "\n";
+
+ }
+
+ catch (MagicsException& e) {
+ MagLog::error() << e << "\n";
+ }
}
void GribLambertInterpretor::print(ostream& out) const {
- out << "GribLambertInterpretor[";
- out << "]";
+ out << "GribLambertInterpretor[";
+ out << "]";
}
PaperPoint GribLambertAzimutalInterpretor::reference(const GribDecoder&, const Transformation&)
{
- assert(false);
-
+ return PaperPoint();
}
void GribPolarStereoInterpretor::print(ostream& out) const {
- out << "GribLambertInterpretor[";
- out << "]";
+ out << "GribLambertInterpretor[";
+ out << "]";
}
void GribPolarStereoInterpretor::interpretAsMatrix(const GribDecoder& grib,
- Matrix** matrix) const {
- long im = 3600;
- long jm = 1800;
+ Matrix** matrix) const {
+ long im = 3600;
+ long jm = 1800;
+
+ *matrix = new Matrix(im, jm);
+ double steplon= 0.1;
+
+ double steplat= 0.1;
- *matrix = new Matrix(im, jm);
- double steplon= 0.1;
- double lon0 = 0 - (steplon/2);
- double steplat= 0.1;
- double lat0 = -90 - (steplat/2);
- double missing = grib.getDouble("missingValue");
- for (int i = 0; i < im; i++) {
- double x = 0 + (i*steplon);
- (*matrix)->columnsAxis().push_back(x);
+ double missing = grib.getDouble("missingValue");
+ for (int i = 0; i < im; i++) {
+ double x = 0 + (i*steplon);
+ (*matrix)->columnsAxis().push_back(x);
- }
+ }
- for (int i = 0; i < jm; i++) {
- double y = -90 + (i*steplat);
- (*matrix)->rowsAxis().push_back(y);
+ for (int i = 0; i < jm; i++) {
+ double y = -90 + (i*steplat);
+ (*matrix)->rowsAxis().push_back(y);
- }
- vector<double> distance(im*jm, 999999);
+ }
+ vector<double> distance(im*jm, 999999);
- for (int i = 0; i < im; i++) {
- for (int j = 0; j < jm; j++)
- (**matrix)[i + (j * im)] = missing;
- }
- (*matrix)->missing(missing);
- (*matrix)->setMapsAxis();
+ for (int i = 0; i < im; i++) {
+ for (int j = 0; j < jm; j++)
+ (**matrix)[i + (j * im)] = missing;
+ }
+ (*matrix)->missing(missing);
+ (*matrix)->setMapsAxis();
- interpolate(grib, **matrix);
+ interpolate(grib, **matrix);
- MagLog::dev() << **matrix << "\n";
+ MagLog::dev() << **matrix << "\n";
@@ -1703,38 +2117,38 @@ void GribPolarStereoInterpretor::interpretAsMatrix(const GribDecoder& grib,
void GribInterpretor::interpolate(const GribDecoder& grib, Matrix& matrix) const
{
- int err;
-
- grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
- if ( err ) {
- MagLog::warning() << "Grib Iterator not available : Chech Grib Api Version " << grib_get_api_version() << endl;
- return;
- }
- double xres = matrix.XResolution();
- double yres = matrix.YResolution();
-
- double xbase = matrix.left() - (xres/2);
- double ybase = matrix.bottom() - (yres/2);
- double columns = matrix.columns();
- double rows = matrix.rows();
-
- vector<double> distance(columns*rows, 999999);
-
- double lat, lon, value;
- /* Loop on all the lat/lon/values. */
- while (grib_iterator_next(iter, &lat, &lon, &value)) {
- int ix = (lon - xbase )/xres;
- double x = (ix * xres) + xbase;
- int iy = (lat - ybase )/yres;
- double y = (iy * yres) + ybase;
- double dist = ((lon - x)*(lon - x)) + ((lat - y)*(lat - y));
- if ( dist < distance[ix + (iy * columns)] ) {
- matrix[ix + (iy * columns)] = value;
- distance[ix + (iy * columns)]= dist;
- }
- }
- /* At the end the iterator is deleted to free memory. */
- grib_iterator_delete(iter);
+ int err;
+
+ grib_iterator* iter = grib_iterator_new(grib.handle(), 0, &err);
+ if ( err ) {
+ MagLog::warning() << "Grib Iterator not available : Chech Grib Api Version " << grib_get_api_version() << endl;
+ return;
+ }
+ double xres = matrix.XResolution();
+ double yres = matrix.YResolution();
+
+ double xbase = matrix.left() - (xres/2);
+ double ybase = matrix.bottom() - (yres/2);
+ double columns = matrix.columns();
+ double rows = matrix.rows();
+
+ vector<double> distance(columns*rows, 999999);
+
+ double lat, lon, value;
+ /* Loop on all the lat/lon/values. */
+ while (grib_iterator_next(iter, &lat, &lon, &value)) {
+ int ix = (lon - xbase )/xres;
+ double x = (ix * xres) + xbase;
+ int iy = (lat - ybase )/yres;
+ double y = (iy * yres) + ybase;
+ double dist = ((lon - x)*(lon - x)) + ((lat - y)*(lat - y));
+ if ( dist < distance[ix + (iy * columns)] ) {
+ matrix[ix + (iy * columns)] = value;
+ distance[ix + (iy * columns)]= dist;
+ }
+ }
+ /* At the end the iterator is deleted to free memory. */
+ grib_iterator_delete(iter);
diff --git a/src/decoders/GribRegularInterpretor.h b/src/decoders/GribRegularInterpretor.h
index 0a369af..5fab4a9 100644
--- a/src/decoders/GribRegularInterpretor.h
+++ b/src/decoders/GribRegularInterpretor.h
@@ -48,10 +48,13 @@ public:
virtual void interpretAsRaster(const GribDecoder&, RasterData&, const Transformation&) const;
virtual void latitudes(const GribDecoder&, vector<double>&) const;
virtual double longitudeIncrement(const GribDecoder&) const;
+ void index(const GribDecoder& grib);
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream&) const;
+
private:
//! Copy constructor - No copy allowed
GribRegularInterpretor(const GribRegularInterpretor&);
@@ -75,6 +78,7 @@ public:
void interpretAsMatrix(const GribDecoder&, Matrix**) const;
void interpretAsMatrix(const GribDecoder&, Matrix**, const Transformation&) const;
void interpretAsRaster(const GribDecoder&, RasterData&, const Transformation&) const;
+ void index(const GribDecoder& grib);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
@@ -152,6 +156,8 @@ public:
UserPoint unrotate(double lat, double lon) const;
void interpretAsMatrix(const GribDecoder&, Matrix**) const;
PaperPoint reference(const GribDecoder&, const Transformation&);
+ double XResolution(const GribDecoder& grib) const;
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream&) const;
diff --git a/src/decoders/GribSatelliteInterpretor.cc b/src/decoders/GribSatelliteInterpretor.cc
index 4f60d40..6557835 100644
--- a/src/decoders/GribSatelliteInterpretor.cc
+++ b/src/decoders/GribSatelliteInterpretor.cc
@@ -212,20 +212,15 @@ int geocoord2pixcoord(double latitude, double longitude, int coff, int loff,
return (-1);
}
-
/* the forward projection is x and y */
-
xx = atan( (-r2/r1) );
yy = asin( (-r3/rn) );
-
/* convert to pixel column and row using the scaling functions on */
/* page 28, Ref. [1]. And finding nearest integer value for them. */
-
- cc = coff + xx * pow(2,-16) * cfac ;
- ll = loff + yy * pow(2,-16) * lfac ;
-
+ cc = coff + xx * pow(2.,-16) * cfac ;
+ ll = loff + yy * pow(2.,-16) * lfac ;
ccc=nint(cc);
lll=nint(ll);
@@ -233,14 +228,11 @@ int geocoord2pixcoord(double latitude, double longitude, int coff, int loff,
*column = ccc;
*row = lll;
-
return (0);
-
}
-
GribSatelliteInterpretor::GribSatelliteInterpretor()
{
}
diff --git a/src/decoders/ImportAction.h b/src/decoders/ImportAction.h
index e501395..ec05567 100644
--- a/src/decoders/ImportAction.h
+++ b/src/decoders/ImportAction.h
@@ -87,7 +87,7 @@ public:
virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, bool ) {}
//! Method to access the data as a list of points
// needMissing : if true the list will contain all the points (If they are outside the area: They will be flagged missing)
- virtual PointsHandler& points(const Transformation&, bool) { assert(false); }
+ virtual PointsHandler& points(const Transformation&, bool) { NOTIMP; }
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream& out) const { out << "ImportAction["; ImportActionAttributes::print(out); out << "]"; }
diff --git a/src/decoders/InputData.cc b/src/decoders/InputData.cc
index 008df3d..0614f8e 100644
--- a/src/decoders/InputData.cc
+++ b/src/decoders/InputData.cc
@@ -285,6 +285,14 @@ void InputData::getReady(const Transformation& transformation)
catch (...) {}
}
+pair<double, double> adjust(double min, double max) {
+
+ double epsilon = max > min ? 0.00001 : -0.00001;
+ min = min - (min*epsilon);
+ max = max + (max*epsilon);
+
+ return make_pair(min, max);
+}
void InputData::visit(Transformation& transformation)
{
@@ -304,13 +312,15 @@ void InputData::visit(Transformation& transformation)
if ( min > *x ) min = *x;
if ( max < *x ) max = *x;
}
- if ( magCompare(x_type_, "date" ) ) {
+ pair<double, double> minmax = adjust(min, max);
+
- transformation.setDataMinMaxX(min, max, baseDateX_);
+ if ( magCompare(x_type_, "date" ) ) {
+ transformation.setDataMinMaxX(minmax.first, minmax.second, baseDateX_);
}
else {
- transformation.setMinMaxX(min, max);
+ transformation.setMinMaxX(minmax.first, minmax.second);
}
}
@@ -327,12 +337,13 @@ void InputData::visit(Transformation& transformation)
if ( min > *y ) min = *y;
if ( max < *y ) max = *y;
}
+ pair<double, double> minmax = adjust(min, max);
if ( magCompare(y_type_, "date" ) ) {
- transformation.setDataMinMaxY(min, max, baseDateY_);
+ transformation.setDataMinMaxY(minmax.first, minmax.second, baseDateY_);
}
else {
- transformation.setMinMaxY(min, max);
+ transformation.setMinMaxY(minmax.first, minmax.second);
}
}
diff --git a/src/decoders/InputMatrix.cc b/src/decoders/InputMatrix.cc
index 7461502..2cfbfd0 100644
--- a/src/decoders/InputMatrix.cc
+++ b/src/decoders/InputMatrix.cc
@@ -30,6 +30,7 @@
#include "InputMatrix.h"
#include "Transformation.h"
#include "Timer.h"
+#include "MagJSon.h"
#include <limits>
using namespace magics;
@@ -49,7 +50,6 @@ InputMatrix::InputMatrix(): matrix_(0), u_(0), v_(0), speed_(0), direction_(0)
InputMatrix::~InputMatrix()
{
}
-
/*!
Class information are given to the output-stream.
*/
@@ -77,7 +77,15 @@ void InputMatrix::filter(Matrix& data)
if ( data[i] <= suppress_below_ || data[i] >= suppress_above_ )
data[i] = data.missing();
}
+void InputMatrix::visit(MetaDataCollector& visitor)
+{
+ ParamJSon data = ParamJSon(metadata_);
+ for(map<string, string>::iterator key = data.begin(); key != data.end(); ++key )
+ {
+ visitor.insert(make_pair(key->first, key->second));
+ }
+}
void InputMatrix::getReady(const Transformation& transformation)
{
@@ -246,3 +254,5 @@ void InputMatrix::customisedPoints(const BasicThinningMethod& thinning, const Tr
delete inx;
delete iny;
}
+
+
diff --git a/src/decoders/InputMatrix.h b/src/decoders/InputMatrix.h
index 73b67e0..41512dc 100644
--- a/src/decoders/InputMatrix.h
+++ b/src/decoders/InputMatrix.h
@@ -60,7 +60,7 @@ public:
void customisedPoints(const Transformation& t, const std::set<string>& n, CustomisedPointsList& out, bool all)
{}
PointsHandler& points(const Transformation& t, bool) { return points(t); }
-
+ double scale(double);
bool defined()
{
return !field_.empty() ||
@@ -72,6 +72,7 @@ public:
}
void filter(Matrix&);
void release();
+ void visit(MetaDataCollector&);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
diff --git a/src/decoders/InputMatrixInterpretor.cc b/src/decoders/InputMatrixInterpretor.cc
index 69eab5e..977f9d8 100644
--- a/src/decoders/InputMatrixInterpretor.cc
+++ b/src/decoders/InputMatrixInterpretor.cc
@@ -29,6 +29,7 @@
#include "InputMatrixInterpretor.h"
#include "InputMatrix.h"
+#include "GribDecoder.h"
#include <limits>
using namespace magics;
@@ -85,10 +86,21 @@ Matrix* InputMatrixRegularInterpretor::geoInterpret(Matrix* in, const InputMatri
else
(this->*mapper->second)();
+
+
+
if ( in->columnsAxis().empty() == false )
// The initialisation has already been done return;
return in;
+ //Apply scaling !
+ double scaling;
+ double offset;
+ GribDecoder::scale(info.metadata_, scaling, offset);
+ for ( int i = 0; i < in->size(); ++i)
+ (*in)[i] = ((*in)[i] * scaling) + offset;
+
+
int nblon = in->columns();
double lon = longitude_;
@@ -108,7 +120,7 @@ Matrix* InputMatrixRegularInterpretor::geoInterpret(Matrix* in, const InputMatri
in->setMapsAxis();
in->missing(std::numeric_limits<double>::max());
return in;
- }
+}
Matrix* InputMatrixRegularInterpretor::xyInterpret(Matrix* in, const InputMatrix& info)
{
@@ -185,9 +197,14 @@ Matrix* InputMatrixIrregularInterpretor::geoInterpret(Matrix* in, const InputMat
vector<double>& values = matrix->values();
vector<double>& rows = matrix->rowsArray();
vector<double>& columns = matrix->columnsArray();
-
+
+ double scaling;
+ double offset;
+ GribDecoder::scale(info.metadata_, scaling, offset);
+ for ( int i = 0; i < in->size(); ++i)
+ (*in)[i] = ((*in)[i] * scaling) + offset;
for (vector<double>::iterator val = in->begin(); val != in->end(); ++val) {
- values.push_back(*val);
+ values.push_back( ((*val) * scaling ) + offset);
}
diff --git a/src/decoders/LandgramDecoder.cc b/src/decoders/LandgramDecoder.cc
index ed03970..1648f48 100644
--- a/src/decoders/LandgramDecoder.cc
+++ b/src/decoders/LandgramDecoder.cc
@@ -39,7 +39,7 @@ LandgramDecoder::LandgramDecoder(): first_(0)
{
/*
ifstream f("/home/graphics/cgs/public/map.txt");
- assert(f);
+ ASSERT(f);
int rows, columns;
double lon, lat, inclon, inclat;
f >> rows >> columns;
diff --git a/src/decoders/MatrixTestDecoder.cc b/src/decoders/MatrixTestDecoder.cc
index 44f3065..e6ff00b 100644
--- a/src/decoders/MatrixTestDecoder.cc
+++ b/src/decoders/MatrixTestDecoder.cc
@@ -39,7 +39,7 @@ MatrixTestDecoder::MatrixTestDecoder()
{
ifstream f("/home/graphics/cgs/public/map.txt");
- assert(f);
+ ASSERT(f);
int rows, columns;
double lon, lat, inclon, inclat;
f >> rows >> columns;
diff --git a/src/decoders/MatrixTestDecoder.h b/src/decoders/MatrixTestDecoder.h
index 5727dbe..1737989 100644
--- a/src/decoders/MatrixTestDecoder.h
+++ b/src/decoders/MatrixTestDecoder.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file MatrixTestDecoder.h
\brief Definition of the Template class MatrixTestDecoder.
-
+
Magics Team - ECMWF 2004
-
+
Started: Thu 25-Mar-2004
-
+
Changes:
-
+
*/
#ifndef MatrixTestDecoder_H
@@ -48,14 +48,15 @@ public:
void decode() {}
virtual void set(const map<string, string>& ) {}
-
+
void customisedPoints(const Transformation& t, const std::set<string>& n, CustomisedPointsList& out, bool all)
- {
- assert(false);
- }
- PointsHandler& points(const Transformation& t, bool) { assert(false); }
-
-
+ {
+ NOTIMP;
+ }
+
+ PointsHandler& points(const Transformation& t, bool) { NOTIMP; }
+
+
PointsHandler& points() { throw MethodNotYetImplemented("MatrixTestDecoder::points()"); }
virtual MatrixHandler& matrix()
{
@@ -66,7 +67,7 @@ public:
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
+ virtual void print(ostream&) const;
Matrix matrix_;
private:
diff --git a/src/decoders/Netcdf.cc b/src/decoders/Netcdf.cc
index 7aa9479..0dff5a0 100644
--- a/src/decoders/Netcdf.cc
+++ b/src/decoders/Netcdf.cc
@@ -135,13 +135,13 @@ struct Index
}
virtual int operator()(const string& val, NcValues* values, long nb )
{
- assert(false);
+ ASSERT(false);
}
static int get(const NcType& type, const string& val, NcValues* values, long nb)
{
map<NcType, Index*>::const_iterator tool = tools_->find(type);
if ( tool == tools_->end() ) {
- assert(false);
+ ASSERT(false);
throw new MagicsException("No Index available");
}
diff --git a/src/decoders/NetcdfDecoder.h b/src/decoders/NetcdfDecoder.h
index 1cdc977..d6efffd 100644
--- a/src/decoders/NetcdfDecoder.h
+++ b/src/decoders/NetcdfDecoder.h
@@ -91,7 +91,8 @@ public:
(*interpretor_).customisedPoints(request, out);
}
void customisedPoints(const Transformation& transformation, const std::set<string>& request, CustomisedPointsList& out) {
- (*interpretor_).customisedPoints(transformation, request, out);
+
+ (*interpretor_).customisedPoints(transformation, request, out, thinningFactor_);
}
void visit(AnimationStep& step) {
diff --git a/src/decoders/NetcdfGeoMatrixInterpretor.cc b/src/decoders/NetcdfGeoMatrixInterpretor.cc
index 4ea044e..b48f70d 100644
--- a/src/decoders/NetcdfGeoMatrixInterpretor.cc
+++ b/src/decoders/NetcdfGeoMatrixInterpretor.cc
@@ -210,7 +210,7 @@ void NetcdfGeoMatrixInterpretor::visit(ValuesCollector& vcp,PointsList&)
{
vcp.setCollected(true);
- assert(matrix_);
+ ASSERT(matrix_);
const Transformation& transformation = vcp.transformation();
MatrixHandler* box = transformation.prepareData(*matrix_);
for (ValuesCollector::iterator point = vcp.begin(); point != vcp.end(); ++point) {
@@ -218,7 +218,7 @@ void NetcdfGeoMatrixInterpretor::visit(ValuesCollector& vcp,PointsList&)
}
}
-void NetcdfGeoMatrixInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& out)
+void NetcdfGeoMatrixInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& out, int thinning)
{
Netcdf netcdf(path_, dimension_method_);
@@ -242,8 +242,8 @@ void NetcdfGeoMatrixInterpretor::customisedPoints(const Transformation& transfor
netcdf.get(latitude_, latitudes, first, last);
unsigned int val = 0;
- for (unsigned int lat =0 ; lat < latitudes.size(); lat+=latitude_sample_) {
- for ( unsigned int lon = 0; lon < longitudes.size(); lon+=longitude_sample_) {
+ for (unsigned int lat =0 ; lat < latitudes.size(); lat+=thinning) {
+ for ( unsigned int lon = 0; lon < longitudes.size(); lon+=thinning) {
val = (lat* longitudes.size() + lon);
if ( val >= xcomponent.size() ) return;
if ( val >= ycomponent.size() ) return;
diff --git a/src/decoders/NetcdfGeoMatrixInterpretor.h b/src/decoders/NetcdfGeoMatrixInterpretor.h
index ba6b9aa..88769f5 100644
--- a/src/decoders/NetcdfGeoMatrixInterpretor.h
+++ b/src/decoders/NetcdfGeoMatrixInterpretor.h
@@ -74,7 +74,7 @@ public:
virtual void statsData(map<string,vector<double> >&);
virtual void visit(MetaDataCollector&);
virtual void visit(ValuesCollector&,PointsList&);
- void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&);
+ void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream&) const;
diff --git a/src/decoders/NetcdfGeopointsInterpretor.cc b/src/decoders/NetcdfGeopointsInterpretor.cc
index 1bb053f..24cea24 100644
--- a/src/decoders/NetcdfGeopointsInterpretor.cc
+++ b/src/decoders/NetcdfGeopointsInterpretor.cc
@@ -437,7 +437,7 @@ void NetcdfXYpointsInterpretor::visit(Transformation& transformation)
catch ( ... ) {}
}
-void NetcdfXYpointsInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>& needs, CustomisedPointsList& out)
+void NetcdfXYpointsInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>& needs, CustomisedPointsList& out, int)
{
refDateX_ = transformation.getReferenceX();
refDateY_ = transformation.getReferenceY();
diff --git a/src/decoders/NetcdfGeopointsInterpretor.h b/src/decoders/NetcdfGeopointsInterpretor.h
index db833f2..0e3cd42 100644
--- a/src/decoders/NetcdfGeopointsInterpretor.h
+++ b/src/decoders/NetcdfGeopointsInterpretor.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file NetcdfGeopointsInterpretor.h
\brief Definition of the Template class NetcdfGeopointsInterpretor.
-
+
Magics Team - ECMWF 2004
-
+
Started: Tue 17-Feb-2004
-
+
Changes:
-
+
*/
#ifndef NetcdfGeopointsInterpretor_H
@@ -42,59 +42,59 @@ namespace magics {
class NetcdfGeopointsInterpretor: public NetcdfInterpretor, public NetcdfGeopointsInterpretorAttributes {
public:
- NetcdfGeopointsInterpretor();
- virtual ~NetcdfGeopointsInterpretor();
-
- void set(const map<string, string>& params) {
+ NetcdfGeopointsInterpretor();
+ virtual ~NetcdfGeopointsInterpretor();
+
+ void set(const map<string, string>& params) {
MagLog::debug() << "NetcdfGeopointsInterpretor::set(params)" << "\n";
- NetcdfInterpretorAttributes::set(params);
+ NetcdfInterpretorAttributes::set(params);
NetcdfGeopointsInterpretorAttributes::set(params);
}
- void set(const XmlNode& node) {
+ void set(const XmlNode& node) {
MagLog::debug() << "NetcdfGeopointsInterpretor::set(params)" << "\n";
XmlNode netcdf = node;
NetcdfGeopointsInterpretorAttributes::set(node);
netcdf.name("netcdf");
- NetcdfInterpretorAttributes::set(netcdf);
+ NetcdfInterpretorAttributes::set(netcdf);
}
- virtual NetcdfInterpretor* clone() const {
- NetcdfGeopointsInterpretor* object = new NetcdfGeopointsInterpretor();
- object->clone(*this);
- return object;
+ virtual NetcdfInterpretor* clone() const {
+ NetcdfGeopointsInterpretor* object = new NetcdfGeopointsInterpretor();
+ object->clone(*this);
+ return object;
}
void clone(const NetcdfGeopointsInterpretor& other) {
- NetcdfInterpretorAttributes::copy(other);
- NetcdfGeopointsInterpretorAttributes::copy(other);
+ NetcdfInterpretorAttributes::copy(other);
+ NetcdfGeopointsInterpretorAttributes::copy(other);
}
bool interpretAsPoints(PointsList&);
bool interpretAsPoints(PointsList&, const Transformation&);
bool interpretAsMatrix(Matrix**) { throw MagicsException("Not Yet"); }
virtual void visit(MetaDataCollector&);
virtual void visit(ValuesCollector&,PointsList&);
-
-
+
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
-
+ virtual void print(ostream&) const;
+
private:
//! Copy constructor - No copy allowed
- NetcdfGeopointsInterpretor(const NetcdfGeopointsInterpretor&);
+ NetcdfGeopointsInterpretor(const NetcdfGeopointsInterpretor&);
//! Overloaded << operator to copy - No copy allowed
- NetcdfGeopointsInterpretor& operator=(const NetcdfGeopointsInterpretor&);
+ NetcdfGeopointsInterpretor& operator=(const NetcdfGeopointsInterpretor&);
// -- Friends
//! Overloaded << operator to call print().
- friend ostream& operator<<(ostream& s,const NetcdfGeopointsInterpretor& p)
- { p.print(s); return s; }
+ friend ostream& operator<<(ostream& s,const NetcdfGeopointsInterpretor& p)
+ { p.print(s); return s; }
};
class NetcdfXYpointsInterpretor: public NetcdfInterpretor, public NetcdfXYpointsInterpretorAttributes {
public:
- NetcdfXYpointsInterpretor();
- virtual ~NetcdfXYpointsInterpretor();
+ NetcdfXYpointsInterpretor();
+ virtual ~NetcdfXYpointsInterpretor();
void set(const map<string, string>& params) {
MagLog::debug() << "NetcdfGeopointsInterpretor::set(params)" << "\n";
@@ -109,21 +109,21 @@ public:
NetcdfInterpretorAttributes::set(netcdf);
}
- virtual NetcdfInterpretor* clone() const {
- NetcdfXYpointsInterpretor* object = new NetcdfXYpointsInterpretor();
- object->clone(*this);
- return object;
+ virtual NetcdfInterpretor* clone() const {
+ NetcdfXYpointsInterpretor* object = new NetcdfXYpointsInterpretor();
+ object->clone(*this);
+ return object;
}
void clone(const NetcdfXYpointsInterpretor& other) {
- NetcdfInterpretorAttributes::copy(other);
- NetcdfXYpointsInterpretorAttributes::copy(other);
+ NetcdfInterpretorAttributes::copy(other);
+ NetcdfXYpointsInterpretorAttributes::copy(other);
}
bool interpretAsPoints(PointsList&, const std::set<string>&);
bool interpretAsPoints(PointsList&);
bool interpretAsPoints(PointsList&, const Transformation&);
bool interpretAsMatrix(Matrix**) { throw MagicsException("Not Yet"); }
virtual void visit(Transformation&);
- virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&);
+ virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int s);
virtual void visit(MetaDataCollector&);
virtual void visit(ValuesCollector&,PointsList&);
void visit(TextVisitor&);
@@ -131,18 +131,18 @@ public:
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
+ virtual void print(ostream&) const;
private:
//! Copy constructor - No copy allowed
- NetcdfXYpointsInterpretor(const NetcdfXYpointsInterpretor&);
+ NetcdfXYpointsInterpretor(const NetcdfXYpointsInterpretor&);
//! Overloaded << operator to copy - No copy allowed
- NetcdfXYpointsInterpretor& operator=(const NetcdfXYpointsInterpretor&);
+ NetcdfXYpointsInterpretor& operator=(const NetcdfXYpointsInterpretor&);
// -- Friends
//! Overloaded << operator to call print().
- friend ostream& operator<<(ostream& s,const NetcdfXYpointsInterpretor& p)
- { p.print(s); return s; }
+ friend ostream& operator<<(ostream& s,const NetcdfXYpointsInterpretor& p)
+ { p.print(s); return s; }
};
diff --git a/src/decoders/NetcdfInterpretor.cc b/src/decoders/NetcdfInterpretor.cc
index 1123209..307c7d0 100644
--- a/src/decoders/NetcdfInterpretor.cc
+++ b/src/decoders/NetcdfInterpretor.cc
@@ -99,6 +99,8 @@ bool NetcdfInterpretor::reference_date(Netcdf& netcdf, const string& var, const
factors["hours"] = 3600;
factors["days"] = 24*3600;
}
+
+ double missing_value = netcdf.getMissing(var, missing_attribute_);
string date = netcdf.getVariableAttribute(var, "reference_date", "");
if ( date.empty() ) return false;
originals.reserve(coords.size());
@@ -108,9 +110,10 @@ bool NetcdfInterpretor::reference_date(Netcdf& netcdf, const string& var, const
basedate = date;
double diff = ( refdate.empty() ) ? 0 : DateTime(date) - DateTime(refdate) ;
map<string, double>::const_iterator factor = factors.find(units);
+ cout << "last point in days!" << coords.back() << endl;
if ( factor != factors.end() )
- std::transform(coords.begin(), coords.end(), coords.begin(), Multiply(factor->second, std::numeric_limits<double>::max()));
- std::transform(coords.begin(), coords.end(), coords.begin(), Plus(diff, std::numeric_limits<double>::max()));
+ std::transform(coords.begin(), coords.end(), coords.begin(), Multiply(factor->second, missing_value));
+ std::transform(coords.begin(), coords.end(), coords.begin(), Plus(diff, missing_value));
}
bool NetcdfInterpretor::cf_date(Netcdf& netcdf, const string& var, const string& refdate, string& basedate, vector<double>& coords, vector<double>& originals)
@@ -121,10 +124,12 @@ bool NetcdfInterpretor::cf_date(Netcdf& netcdf, const string& var, const string&
if ( factors.empty() ) {
factors["hours"] = 3600;
factors["days"] = 24*3600;
+
}
+ double missing_value = netcdf.getMissing(var, missing_attribute_);
string date = netcdf.getVariableAttribute(var, "long_name", "");
if ( date.empty() ) return false;
- if ( date != "time" ) return false;
+ if ( date != "time" && date != "date and time") return false;
string units = netcdf.getVariableAttribute(var, "units", "");
if ( units.empty() ) return false;
@@ -143,7 +148,7 @@ bool NetcdfInterpretor::cf_date(Netcdf& netcdf, const string& var, const string&
double diff;
map<string, double>::const_iterator factor = factors.find(tokens[0]);
if ( refdate.empty() ) {
- diff = Multiply(factor->second, std::numeric_limits<double>::max())(coords.front());
+ diff = Multiply(factor->second, missing_value)(coords.front());
DateTime newref = DateTime(basedate) + Second(diff);
basedate = newref.tostring("%F %T");
diff = -diff;
@@ -154,8 +159,9 @@ bool NetcdfInterpretor::cf_date(Netcdf& netcdf, const string& var, const string&
if ( factor != factors.end() )
- std::transform(coords.begin(), coords.end(), coords.begin(), Multiply(factor->second, std::numeric_limits<double>::max()));
- std::transform(coords.begin(), coords.end(), coords.begin(), Plus(diff, std::numeric_limits<double>::max()));
+ std::transform(coords.begin(), coords.end(), coords.begin(), Multiply(factor->second, missing_value));
+ std::transform(coords.begin(), coords.end(), coords.begin(), Plus(diff, missing_value));
+
}
string NetcdfInterpretor::getAttribute(const string& var, const string& attr, const string& def)
{
diff --git a/src/decoders/NetcdfInterpretor.h b/src/decoders/NetcdfInterpretor.h
index 011a231..d9665c7 100644
--- a/src/decoders/NetcdfInterpretor.h
+++ b/src/decoders/NetcdfInterpretor.h
@@ -62,7 +62,7 @@ public:
{ MagLog::dev() << "Method NetcdfInterpretor::interpretAsPoints() --> Not yet implemented.\n"; return false; }
virtual void customisedPoints(const std::set<string>&, CustomisedPointsList&)
{ MagLog::dev() << "Method NetcdfInterpretor::customisedPoints() --> Not yet implemented.\n"; }
- virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&)
+ virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int thinning)
{ MagLog::dev() << "Method NetcdfInterpretor::customisedPoints() --> Not yet implemented.\n"; }
virtual bool interpretAsPoints(PointsList& points, const Transformation&)
diff --git a/src/decoders/NetcdfMatrixInterpretor.cc b/src/decoders/NetcdfMatrixInterpretor.cc
index 5c3f1a8..2b76b1f 100644
--- a/src/decoders/NetcdfMatrixInterpretor.cc
+++ b/src/decoders/NetcdfMatrixInterpretor.cc
@@ -330,7 +330,40 @@ void NetcdfMatrixInterpretor::visit(Transformation& transformation)
}
+void NetcdfMatrixInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& points, int thinning)
+{
+ refDateX_ = transformation.getReferenceX();
+ refDateY_ = transformation.getReferenceY();
+
+ Matrix* uc = 0;
+ Matrix* vc = 0;
+ field_ = u_component_;
+ if (!interpretAsMatrix(&uc) )
+ return;
+ field_ = v_component_;
+ if ( !interpretAsMatrix(&vc) )
+ return;
+
+ vector<double>::iterator u = uc->begin();
+ vector<double>::iterator v = vc->begin();
+
+ for (int row = 0; row < rows_.size(); row += thinning)
+ for (int column = 0; column < columns_.size(); column += thinning) {
+
+
+ CustomisedPoint* point = new CustomisedPoint();
+ point->longitude(columns_[column]);
+ point->latitude(rows_[row]);
+ (*point)["x_component"] = (*uc)(row, column);
+ (*point)["y_component"] = (*vc)(row, column);
+
+ ++u;
+ ++v;
+ points.push_back(point);
+ }
+
+}
void NetcdfMatrixInterpretor::statsData(map<string,vector<double> >& stats)
{
if(matrix_)
@@ -372,7 +405,7 @@ void NetcdfMatrixInterpretor::visit(ValuesCollector& vcp,PointsList&)
{
vcp.setCollected(true);
- assert(matrix_);
+ ASSERT(matrix_);
const Transformation& transformation = vcp.transformation();
MatrixHandler* box = transformation.prepareData(*matrix_);
diff --git a/src/decoders/NetcdfMatrixInterpretor.h b/src/decoders/NetcdfMatrixInterpretor.h
index d628830..b0f3097 100644
--- a/src/decoders/NetcdfMatrixInterpretor.h
+++ b/src/decoders/NetcdfMatrixInterpretor.h
@@ -92,6 +92,7 @@ public:
virtual void statsData(map<string,vector<double> >&);
virtual bool x();
virtual bool y();
+ void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int thinning);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
diff --git a/src/decoders/NetcdfOrcaInterpretor.cc b/src/decoders/NetcdfOrcaInterpretor.cc
index 38845b4..f9cf689 100644
--- a/src/decoders/NetcdfOrcaInterpretor.cc
+++ b/src/decoders/NetcdfOrcaInterpretor.cc
@@ -232,7 +232,8 @@ bool NetcdfOrcaInterpretor::interpretAsMatrix(Matrix** data)
(*matrix)[index.second +( index.first*im)] = val;
}
-
+ matrix->multiply(scaling_);
+ matrix->plus(offset_);
}
@@ -313,7 +314,40 @@ bool NetcdfOrcaInterpretor::interpretAsPoints(PointsList& points)
}
+void NetcdfOrcaInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& out, int thinning)
+{
+ try
+ {
+ MagLog::dev() << " Netcdf File Path --->" << path_ << "\n";
+ Netcdf netcdf(path_, dimension_method_);
+ map<string, string> first, last;
+ setDimensions(dimension_, first, last);
+ double missing = netcdf.getMissing(field_, missing_attribute_);
+ vector<double> latitudes;
+ vector<double> longitudes;
+ vector<double> x_component, y_component;
+
+ netcdf.get(longitude_, longitudes, first, last);
+ netcdf.get(latitude_, latitudes, first, last);
+ netcdf.get(u_component_, x_component, first, last);
+ netcdf.get(v_component_, y_component, first, last);
+
+ for ( int ind = 0; ind < latitudes.size(); ind += thinning) {
+ CustomisedPoint* point = new CustomisedPoint();
+ point->longitude(longitudes[ind]);
+ point->latitude(latitudes[ind]);
+ (*point)["x_component"] = x_component[ind];
+ (*point)["y_component"] = y_component[ind];
+ out.push_back(point);
+ }
+ }
+
+ catch (MagicsException& e)
+ {
+ MagLog::error() << e << "\n";
+ }
+}
/*!
Class information are given to the output-stream.
diff --git a/src/decoders/NetcdfOrcaInterpretor.h b/src/decoders/NetcdfOrcaInterpretor.h
index 4d8aa3e..a23333a 100644
--- a/src/decoders/NetcdfOrcaInterpretor.h
+++ b/src/decoders/NetcdfOrcaInterpretor.h
@@ -56,7 +56,8 @@ public:
bool interpretAsPoints(PointsList&);
bool interpretAsMatrix(Matrix**);
-
+ void customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& out, int thinning);
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
diff --git a/src/decoders/NetcdfVectorInterpretor.cc b/src/decoders/NetcdfVectorInterpretor.cc
index e9afaef..0c2c102 100644
--- a/src/decoders/NetcdfVectorInterpretor.cc
+++ b/src/decoders/NetcdfVectorInterpretor.cc
@@ -76,7 +76,7 @@ NetcdfGeoVectorInterpretor::~NetcdfGeoVectorInterpretor()
{
}
-void NetcdfVectorInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& list)
+void NetcdfVectorInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& list, int thinning)
{
Netcdf netcdf(path_, dimension_method_);
try {
@@ -92,36 +92,24 @@ void NetcdfVectorInterpretor::customisedPoints(const Transformation& transformat
netcdf.get(x_, x, first, last);
netcdf.get(y_, y, first, last);
- vector<double>::iterator xi = x.begin();
- vector<double>::iterator yi = y.begin();
- vector<double>::const_iterator u = x_component.begin();
- vector<double>::const_iterator v = y_component.begin();
+ // here we assume that the 4 verctors have the same size
- xi = x.begin();
- yi = y.begin();
- while ( xi != x.end() && yi != y.end() &&
- u != x_component.end() && v != y_component.end() ) {
-// if ( transformation.in( *xi, *yi) ) {
- CustomisedPoint* point = new CustomisedPoint();
- point->longitude(*xi);
- point->latitude(*yi);
- (*point)["x_component"] = *u;
- (*point)["y_component"] = *v;
- list.push_back(point);
-// }
- xi++;
- yi++;
- u++;
- v++;
+ for ( int ind = 0; ind < x.size(); ind += thinning) {
+ CustomisedPoint* point = new CustomisedPoint();
+ point->longitude(x[ind]);
+ point->latitude(y[ind]);
+ (*point)["x_component"] = x_component[ind];
+ (*point)["y_component"] = y_component[ind];
+ list.push_back(point);
}
}
catch (MagicsException& e)
{
MagLog::error() << e << "\n";
- }
+ }
}
-void NetcdfGeoVectorInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& list)
+void NetcdfGeoVectorInterpretor::customisedPoints(const Transformation& transformation, const std::set<string>&, CustomisedPointsList& list, int thinning)
{
Netcdf netcdf(path_, dimension_method_);
try {
@@ -139,8 +127,7 @@ void NetcdfGeoVectorInterpretor::customisedPoints(const Transformation& transfor
vector<double>::iterator lat = latitudes.begin();
vector<double>::iterator lon = longitudes.begin();
- vector<double>::const_iterator x = x_component.begin();
- vector<double>::const_iterator y = y_component.begin();
+
//If the lat-lon units is specified as "radians" convert lat-lon
//to degrees. By default the units are sipposed to be "degrees"
@@ -161,22 +148,15 @@ void NetcdfGeoVectorInterpretor::customisedPoints(const Transformation& transfor
}
}
- lat = latitudes.begin();
- lon = longitudes.begin();
- while ( lat != latitudes.end() && lon != longitudes.end() &&
- x != x_component.end() && y != y_component.end() ) {
- //if ( transformation.in( *lon, *lat) ) {
- CustomisedPoint* point = new CustomisedPoint();
- point->longitude(*lon);
- point->latitude(*lat);
- (*point)["x_component"] = *x;
- (*point)["y_component"] = *y;
- list.push_back(point);
- //}
- lon++;
- lat++;
- x++;
- y++;
+ // here we assume that the 4 verctors have the same size
+
+ for ( int ind = 0; ind < latitudes.size(); ind += thinning) {
+ CustomisedPoint* point = new CustomisedPoint();
+ point->longitude(longitudes[ind]);
+ point->latitude(latitudes[ind]);
+ (*point)["x_component"] = x_component[ind];
+ (*point)["y_component"] = y_component[ind];
+ list.push_back(point);
}
}
catch (MagicsException& e)
diff --git a/src/decoders/NetcdfVectorInterpretor.h b/src/decoders/NetcdfVectorInterpretor.h
index a1de590..52632e0 100644
--- a/src/decoders/NetcdfVectorInterpretor.h
+++ b/src/decoders/NetcdfVectorInterpretor.h
@@ -87,7 +87,7 @@ public:
NetcdfVectorInterpretorAttributes::copy(*this);
}
virtual void customisedPoints(const std::set<string>&, CustomisedPointsList&);
- virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&);
+ virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
@@ -136,7 +136,7 @@ public:
NetcdfInterpretorAttributes::copy(*this);
NetcdfGeoVectorInterpretorAttributes::copy(*this);
}
- virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&);
+ virtual void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, int);
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
diff --git a/src/decoders/ObsDecoder.cc b/src/decoders/ObsDecoder.cc
index bf42fb7..7cf9c00 100644
--- a/src/decoders/ObsDecoder.cc
+++ b/src/decoders/ObsDecoder.cc
@@ -289,7 +289,7 @@ public:
{
const BufrIdentifiers& table = BufrIdentTable::get(obs.originatingCentre());
val = obs.value(table.ident(descriptor_));
- MagLog::dev()<< "BufrAccessor-Descriptor--->" << descriptor_ << " Value--->" << val << endl;
+
}
virtual void print() {}
const string& keyword() { return descriptor_; }
diff --git a/src/decoders/ShapeDecoder.h b/src/decoders/ShapeDecoder.h
index 08d1ee5..2712ba8 100644
--- a/src/decoders/ShapeDecoder.h
+++ b/src/decoders/ShapeDecoder.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file ShapeDecoder.h
\brief Definition of the Template class ShapeDecoder.
-
+
Magics Team - ECMWF 2005
-
+
Started: Mon 12-Dec-2005
-
+
Changes:
-
+
*/
#ifndef ShapeDecoder_H
@@ -45,10 +45,10 @@ typedef boost::geometry::model::polygon< boost::geometry::model::d2::point_xy<do
typedef boost::geometry::model::box< boost::geometry::model::d2::point_xy<double> > box_2d;
namespace magics {
-
+
class XmlNode;
-class ShapeDecoder: public ShapeDecoderAttributes,
+class ShapeDecoder: public ShapeDecoderAttributes,
public Data, public Decoder, public vector<PointsList* >
{
public:
@@ -63,18 +63,19 @@ public:
void set(const map<string, string>& map ) { ShapeDecoderAttributes::set(map); }
void set(const XmlNode& node ) { ShapeDecoderAttributes::set(node); }
void customisedPoints(const std::set<string>&, CustomisedPointsList&);
- void decode() {assert(false);}
+ void decode() {ASSERT(false);}
void needHoles(bool holes) { holes_ = holes; }
void setPath(const string& path) { path_ = path; }
PointsHandler& points()
{
- assert(false);
+ NOTIMP;
}
PointsHandler& points(const Transformation&, bool )
{
- assert(false);
+ NOTIMP;
}
+
void customisedPoints(const Transformation&, const std::set<string>& n, CustomisedPointsList& out, bool)
{
customisedPoints(n, out);
@@ -82,7 +83,7 @@ public:
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
+ virtual void print(ostream&) const;
bool holes_; // Do we need to deal with the holes during decoding!.
//! Method to ensure all inner rings lie within outer ring of polygon
diff --git a/src/decoders/TitleTemplate.h b/src/decoders/TitleTemplate.h
index a826359..3cf7435 100644
--- a/src/decoders/TitleTemplate.h
+++ b/src/decoders/TitleTemplate.h
@@ -76,7 +76,7 @@ class TitleFieldHandler
public :
TitleFieldHandler() {}
virtual ~TitleFieldHandler() {};
- virtual void operator()(TitleField& field, vector<string>& lines, const GribDecoder&) { assert (false); }
+ virtual void operator()(TitleField& field, vector<string>& lines, const GribDecoder&) { ASSERT (false); }
};
diff --git a/src/drivers/BaseDriver.cc b/src/drivers/BaseDriver.cc
index 7cebf62..9eafa0b 100644
--- a/src/drivers/BaseDriver.cc
+++ b/src/drivers/BaseDriver.cc
@@ -38,7 +38,7 @@
#include <Image.h>
#include <Symbol.h>
#include <PaperPoint.h>
-#include "AnimationRules.h"
+//#include "AnimationRules.h"
#include <BaseDriverSymbols.h>
#include <BaseDriverWind.h>
@@ -342,8 +342,6 @@ void BaseDriver::redisplay(const Polyline& line) const
{
if(line.isFilled()) renderSimplePolygon(line);
if(line.isStroked()) printLine(line);
-// ArrowProperties* pArrowProperties = line.arrowProperties();
-// if(pArrowProperties)
}
void BaseDriver::redisplay(const Arrow& arrow) const
@@ -415,7 +413,7 @@ double BaseDriver::LSF(MFloat *x,MFloat *y, int i0) const
double angle = 0.;
double x_sum = 0.;
double y_sum = 0.;
- const unsigned int n = 15;
+ const unsigned int n = 3;
for(unsigned int r=0;r<n;r++)
{
@@ -435,9 +433,17 @@ double BaseDriver::LSF(MFloat *x,MFloat *y, int i0) const
sxx += (xi*xi);
sxy += (xi*yi);
}
- if(sxx != 0) angle = atan2( (sxy/sxx) ,1.);
- else MagLog::debug() << "BaseDriver: Devision through zero prevented in calculation of Label angle!" << endl;
+// if( (abs(sxx) > 0.00001) && (abs(sxy) > 0.00001) ) angle = atan2( (sxy/sxx) ,1.);
+ if( (abs(sxx) > 0.00001) )
+ {
+ angle = atan2( (sxy/sxx) ,1.);
+ }
+ else
+ {
+ angle=10.;
+ MagLog::warning() << "BaseDriver: Devision through zero prevented in calculation of Label angle!" << endl;
+ }
return angle;
}
@@ -451,7 +457,9 @@ double BaseDriver::LSF(MFloat *x,MFloat *y, int i0) const
void BaseDriver::printLine(const Polyline &line) const
{
const unsigned long n = line.size();
- if(n < 1) return;
+ if(n < 2) return;
+
+ bool arrowHead = (line.arrowProperties()) ? true :false;
MFloat *x = new MFloat[n];
MFloat *y = new MFloat[n];
@@ -465,18 +473,18 @@ void BaseDriver::printLine(const Polyline &line) const
// render line - driver specific part
if(line.getThickness()>0 && !(line.getColour()==Colour("NONE")) )
{
- setNewColour(line.getColour());
- currentLineStyle_ = setLineParameters(line.getLineStyle(),line.getThickness());
+ setNewColour(line.getColour());
+ currentLineStyle_ = setLineParameters(line.getLineStyle(),line.getThickness());
-// if(line.getAntiAliasing()) polylineAntialiasing_=true;
- renderPolyline(n, x, y);
-// polylineAntialiasing_=false;
+// if(line.getAntiAliasing()) polylineAntialiasing_=true;
+ renderPolyline(n, x, y);
+// polylineAntialiasing_=false;
- Polyline::Holes::const_iterator h = line.beginHoles();
- Polyline::Holes::const_iterator he = line.endHoles();
+ Polyline::Holes::const_iterator h = line.beginHoles();
+ Polyline::Holes::const_iterator he = line.endHoles();
- for (; h != he; ++h)
- {
+ for (; h != he; ++h)
+ {
vector<double> xx;
vector<double> yy;
line.hole(h,xx,yy);
@@ -491,40 +499,41 @@ void BaseDriver::printLine(const Polyline &line) const
renderPolyline(nn, nx, ny);
delete [] nx;
delete [] ny;
- }
+ }
}
- const unsigned int minimum_points_for_labelling = 32; // must be at least -15 : see function LSF above
+ const unsigned int minimum_points_for_labelling = 25; // must be at least -15 : see function LSF above
- if (line.getLabel().isVisible() && line.getLabel().getText() != "" && (n > minimum_points_for_labelling))
+ if ( (arrowHead || (line.getLabel().isVisible() && line.getLabel().getText() != "") ) && (n > minimum_points_for_labelling))
{
- assert(staLayouts_.empty() == false);
-
- MFloat *labelx = new MFloat[n]; // in theory, we shouldn't need this many entries...
- MFloat *labely = new MFloat[n]; // in theory, we shouldn't need this many entries...
-
- // Store the minimum x,y corner, pretending that we're going to plot a label there.
- // We won't actually plot a label there though - it's just to make sure that
- // we don't plot one too close to that point.
- int num_labels = 1;
- labelx [0] = staLayouts_.top()->minX();
- labely [0] = staLayouts_.top()->minY();
-
- // Calculate how far apart the labels should be.
- // Our algorithm is to take the average of the width and height and divide by 2.
- // This should give us approximately 3 labels over the width of the page.
- const MFloat coords_range_x = fabs(staLayouts_.top()->maxX()-staLayouts_.top()->minX());
- const MFloat coords_range_y = fabs(staLayouts_.top()->maxY()-staLayouts_.top()->minY());
- const MFloat min_distance_between_labels = (coords_range_x + coords_range_y) / 4.;
- const MFloat min_square_distance_between_labels = (min_distance_between_labels * min_distance_between_labels);
-
- unsigned int i = 15;
- while(i < n-minimum_points_for_labelling)
- {
- const double angle = LSF(x,y,i);
- const double angle2 = LSF(x,y,i+1);
- if(fabs(angle-angle2)< 0.01)
+ ASSERT(staLayouts_.empty() == false);
+
+ MFloat *labelx = new MFloat[n]; // in theory, we shouldn't need this many entries...
+ MFloat *labely = new MFloat[n]; // in theory, we shouldn't need this many entries...
+
+ // Store the minimum x,y corner, pretending that we're going to plot a label there.
+ // We won't actually plot a label there though - it's just to make sure that
+ // we don't plot one too close to that point.
+ int num_labels = 1;
+ labelx [0] = staLayouts_.top()->minX();
+ labely [0] = staLayouts_.top()->minY();
+
+ // Calculate how far apart the labels should be.
+ // Our algorithm is to take the average of the width and height and divide by 2.
+ // This should give us approximately 3 labels over the width of the page.
+ const MFloat coords_range_x = fabs(staLayouts_.top()->maxX()-staLayouts_.top()->minX());
+ const MFloat coords_range_y = fabs(staLayouts_.top()->maxY()-staLayouts_.top()->minY());
+ const MFloat min_distance_between_labels = (coords_range_x + coords_range_y) / 4.;
+ const MFloat min_square_distance_between_labels = (min_distance_between_labels * min_distance_between_labels);
+
+ unsigned int i = 10;
+ while(i < n-minimum_points_for_labelling)
{
+ double angle = LSF(x,y,i);
+ const double angle2 = LSF(x,y,i+1);
+
+ if( (angle <4.) && (angle2 <4.) && fabs(angle-angle2)< 0.01)
+ {
const MFloat THIS_X = x[i];
const MFloat THIS_Y = y[i];
const MFloat PREV_X = labelx[num_labels - 1];
@@ -532,44 +541,82 @@ void BaseDriver::printLine(const Polyline &line) const
const double distance_squared = ((THIS_X - PREV_X) * (THIS_X - PREV_X)) + ((THIS_Y - PREV_Y) * (THIS_Y - PREV_Y));
- if (distance_squared > min_square_distance_between_labels)
+ if ( (arrowHead) || (distance_squared > min_square_distance_between_labels) )
{
- // line fitting
- MFloat pro_x = x[i+2];
- MFloat pro_y = y[i+2]; // lines not needed
- // end of line fitting
-
- Text text;
- PaperPoint pp(pro_x,pro_y);
- text.push_back(pp);
-
- Label label= line.getLabel();
- MagFont font = label.font();
-
- text.setFont(font);
- text.addText(label.getText(),font.colour(),font.size());
- text.setBlanking(label.getBlanking());
- text.setJustification(label.getJustification());
- text.setVerticalAlign(MHALF);
-
- text.setAngle(-setAngleY(angle));
- text.setFont(font);
- renderText(text);
-
- labelx [num_labels] = x[i];
- labely [num_labels] = y[i];
- num_labels++;
- }
- }//angles are not the same
- i++;i++;
- }
- delete [] labelx;
- delete [] labely;
+ if(arrowHead)
+ {
+ MFloat pro_x = x[i];
+ MFloat pro_y = y[i];
+
+ Arrow arrow;
+ arrow.copy(*line.arrowProperties());
+ arrow.setColour(line.getColour());
+ arrow.setArrowPosition(M_HEAD_ONLY);
+// arrow.setHeadRatio(1.5);
+// arrow.setHeadIndex(1);
+ if( (x[i]-x[i+3]) < 0.) angle += PI;
+ const double dx=sin(angle+1.5707963267949);
+ const double dy=-setAngleY(cos(angle+1.5707963267949));
+ PaperPoint pp(pro_x,pro_y);
+ ArrowPoint apoint(dx,dy,pp);
+ arrow.push_back(apoint);
+ renderWindArrow(arrow);
+/*
+ {
+ cout << "STREAMLINES >>>>>>>>>>>>>>>>>>> angle: " << angle<<" x:"<<pro_x<<" y:"<<pro_y<< endl;
+ int ewn=5;
+ setNewColour(Colour("red"));
+ setNewLineWidth(4.);
+ renderPolyline(ewn, &x[i], &y[i]);
+
+ TextSymbol textSymbol;
+ textSymbol.position(TextSymbol::M_BELOW);
+ ostringstream nice;
+ nice << angle;
+ textSymbol.push_back(pp, nice.str());
+ renderTextSymbols(textSymbol);
+ }
+*/
+ }
+ else
+ {
+ MFloat pro_x = x[i+2];
+ MFloat pro_y = y[i+2];
+ Text text;
+ PaperPoint pp(pro_x,pro_y);
+ text.push_back(pp);
+ Label label= line.getLabel();
+ MagFont font = label.font();
+ text.setFont(font);
+ text.addText(label.getText(),font.colour(),font.size());
+ text.setBlanking(label.getBlanking());
+ text.setJustification(label.getJustification());
+ text.setVerticalAlign(MHALF);
+ text.setAngle(-setAngleY(angle));
+ text.setFont(font);
+ renderText(text);
+ }
+ labelx [num_labels] = x[i];
+ labely [num_labels] = y[i];
+ num_labels++;
+ i+=5;
+ }
+ }//angles are not the same
+ i+=5;
+ }
+ delete [] labelx;
+ delete [] labely;
}// endif enough points for a label
-
+/*
+ {
+ int ewn=2;
+ setNewColour(Colour("red"));
+ setNewLineWidth(4.);
+ renderPolyline(ewn, x, y);
+ }
+*/
delete [] x;
delete [] y;
-
currentColour_ = Colour("none");
}
@@ -975,30 +1022,29 @@ void BaseDriver::redisplay(const BinaryObject& binary) const
}
break;
- case 'I':
+ case 'I': // Images
{
MFloat x0=0.;
MFloat x1=0.;
MFloat y0=0.;
MFloat y1 = 0.;
- int he=0;
- int wi=0;
- int si=0;
+ int height=0;
+ int width=0;
+ int noOfColours=0;
double red=0.;double green=0.;double blue=0.;double alpha=0.;
- in.read((char *)(&wi), sizeof(int));
- in.read((char *)(&he), sizeof(int));
+ in.read((char *)(&width), sizeof(int));
+ in.read((char *)(&height), sizeof(int));
in.read((char *)(&x0), sizeof(MFloat));
in.read((char *)(&y0), sizeof(MFloat));
in.read((char *)(&x1), sizeof(MFloat));
in.read((char *)(&y1), sizeof(MFloat));
- const int d=wi*he;
+ const int d=width*height;
- in.read((char *)(&si), sizeof(int));
+ in.read((char *)(&noOfColours), sizeof(int));
ColourTable table;
-
- for(int v=0;v<si;v++)
+ for(int v=0;v<noOfColours;v++)
{
in.read((char *)(&red ), sizeof(double));
in.read((char *)(&green), sizeof(double));
@@ -1007,18 +1053,19 @@ void BaseDriver::redisplay(const BinaryObject& binary) const
table.push_back(ColourTableEntry(Colour(red,green,blue,alpha)));
}
- short cc[d];
- in.read((char *)(cc), sizeof(short)*d);
+ short *pixels = new short[d];
+ in.read((char *)(pixels), sizeof(short)*d);
Image object;
PaperPoint pp(x0,y0,0.);
object.setOrigin(pp);
object.setWidth(x1);
object.setHeight(y1);
- object.set(he,wi);
- for(int i=0;i<d;i++) object.push_back(cc[i]);
+ object.set(height,width);
+ for(int i=0;i<d;i++) object.push_back(pixels[i]); // object(std::begin(pixels), std::end(pixels));
object.setColourTable(table);
renderCellArray(object);
+ delete [] pixels;
}
break;
diff --git a/src/drivers/BaseDriverSymbols.h b/src/drivers/BaseDriverSymbols.h
index 6477e17..0d338c9 100644
--- a/src/drivers/BaseDriverSymbols.h
+++ b/src/drivers/BaseDriverSymbols.h
@@ -117,7 +117,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderTextSymbols(const TextSymbol& symbol) co
const int nPos = symbol.size();
const int nText = symbol.text().size();
- assert(nText >= nPos);
+ ASSERT(nText >= nPos);
if(nText < nPos) MagLog::debug() << " BaseDriverSymbols > Not enough texts ("<<nText<<") for "<<nPos<<" symbols!";
//Loop for all positions
@@ -243,7 +243,11 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbolItem(const SymbolItem& symbol, con
sym = sym_[ii];
if(sym.id==symbol.symbol()) break;
}
- if(ii==noSymbols) sym = sym_[0];
+ if(ii==noSymbols)
+ {
+ sym = sym_[0];
+ MagLog::warning() << "BaseDriver::renderSymbols("<<symbol.symbol()<<")-> symbol NOT available! use question mark."<< std::endl;
+ }
const unsigned int si = sym.elements.size();
const MFloat pX = 1. / coordRatioX_;
@@ -260,7 +264,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbolItem(const SymbolItem& symbol, con
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
const int s = atoi(sym.elements[i].attributes["fill"].c_str());
circle(posX+cx,posY+cy,r,s);
}
@@ -268,14 +272,14 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbolItem(const SymbolItem& symbol, con
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
snowflake(posX+cx,posY+cy,r);
}
else if(sym.elements[i].name == "drizzle")
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
drizzle(posX+cx,posY+cy,r);
}
else if(sym.elements[i].name == "triangle")
@@ -283,7 +287,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbolItem(const SymbolItem& symbol, con
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const int s = atoi(sym.elements[i].attributes["fill"].c_str());
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
const int li = atoi(sym.elements[i].attributes["line"].c_str());
triangle(posX+cx,posY+cy,r,s,li);
}
@@ -291,7 +295,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbolItem(const SymbolItem& symbol, con
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
lightning(posX+cx,posY+cy,r);
}
if(sym.elements[i].name == "polyline")
@@ -360,7 +364,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbols(const Symbol& symbol) const
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = setY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
+ const MFloat cy = setSymbolY(setY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY));
const int s = atoi(sym.elements[i].attributes["fill"].c_str());
for(long l=0;l<n;l++)
{
@@ -380,14 +384,14 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbols(const Symbol& symbol) const
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
for(long l=0;l<n;l++) snowflake(symbol[l].x()+cx,symbol[l].y()+cy,r);
}
else if(sym.elements[i].name == "drizzle")
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
for(long l=0;l<n;l++) drizzle(symbol[l].x()+cx,symbol[l].y()+cy,r);
}
else if(sym.elements[i].name == "triangle")
@@ -395,7 +399,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbols(const Symbol& symbol) const
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const int s = atoi(sym.elements[i].attributes["fill"].c_str());
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
const int li = atoi(sym.elements[i].attributes["line"].c_str());
for(long l=0;l<n;l++)
@@ -416,7 +420,7 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbols(const Symbol& symbol) const
{
const MFloat r = atof(sym.elements[i].attributes["r"].c_str()) * scaling * pX;
const MFloat cx = atof(sym.elements[i].attributes["cx"].c_str()) * scaling * pX;
- const MFloat cy = atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY;
+ const MFloat cy = setSymbolY(atof(sym.elements[i].attributes["cy"].c_str()) * scaling * pY);
for(long l=0;l<n;l++) lightning(symbol[l].x()+cx,symbol[l].y()+cy,r);
}
if(sym.elements[i].name == "polyline")
@@ -461,20 +465,20 @@ MAGICS_NO_EXPORT void BaseDriver::renderSymbols(const Symbol& symbol) const
*/
MAGICS_NO_EXPORT void BaseDriver::snowflake(const MFloat x, const MFloat y, const MFloat size) const
{
- const MFloat s5 = size;
- const MFloat s3 = size * 0.78;
+ const MFloat s5 = size * 1.2;
+ const MFloat s3 = size * 0.75;
vector<PaperPoint> line;
- line.push_back(PaperPoint(x-s5,y));
- line.push_back(PaperPoint(x+s5,y));
+ line.push_back(PaperPoint(x-size,y));
+ line.push_back(PaperPoint(x+size,y));
renderPolyline2(line);
line.clear();
- line.push_back(PaperPoint(x-s3,y+s3));
- line.push_back(PaperPoint(x+s3,y-s3));
+ line.push_back(PaperPoint(x-s3,y+s5));
+ line.push_back(PaperPoint(x+s3,y-s5));
renderPolyline2(line);
line.clear();
- line.push_back(PaperPoint(x-s3,y-s3));
- line.push_back(PaperPoint(x+s3,y+s3));
+ line.push_back(PaperPoint(x-s3,y-s5));
+ line.push_back(PaperPoint(x+s3,y+s5));
renderPolyline2(line);
}
@@ -483,14 +487,35 @@ MAGICS_NO_EXPORT void BaseDriver::snowflake(const MFloat x, const MFloat y, cons
*/
MAGICS_NO_EXPORT void BaseDriver::drizzle(const MFloat x, const MFloat y, const MFloat size) const
{
- const MFloat s2 = size*.4;
+ const MFloat s5 = size*.6;
+ const MFloat s25 = size*.3;
- circle(x,y,s2 * coordRatioX_,8);
+ vector<PaperPoint> line;
+ line.push_back(PaperPoint( x+s25, y-s5) );
+ line.push_back(PaperPoint( x-s25, y-s5) );
+ line.push_back(PaperPoint( x-s5, y-s25));
+ line.push_back(PaperPoint( x-s5, y+s25));
+ line.push_back(PaperPoint( x-s25, y+s5) );
+ line.push_back(PaperPoint( x+s25, y+s5) );
+ line.push_back(PaperPoint( x+s5, y+s25));
+ line.push_back(PaperPoint( x+s5, y-s25));
+ line.push_back(PaperPoint( x+(size*.58), y-(size*.85)));
+ line.push_back(PaperPoint( x+(size*.45), y-(size*1.1)));
+ line.push_back(PaperPoint( x+(size*.1), y-(size*1.4)));
+ line.push_back(PaperPoint( x+s25, y-(size*.7)));
+
+ renderSimplePolygon(line);
+/* circle(x,y,s2 * coordRatioX_,8);
vector<PaperPoint> line;
- line.push_back(PaperPoint(x+(s2*0.9),y));
- line.push_back(PaperPoint(x-size*0.3,y-size*1.25));
- renderPolyline2(line);
+ line.push_back(PaperPoint(x+ s2 ,y));
+ line.push_back(PaperPoint(x+ s2 ,y-(s2*1.75)));
+ line.push_back(PaperPoint(x ,y-(s2*1.95)));
+ line.push_back(PaperPoint(x ,y-(s2*1.77)));
+ line.push_back(PaperPoint(x+(s2*0.4) ,y-(s2*1.25)));
+ line.push_back(PaperPoint(x+(s2*0.4) ,y-s2));
+ renderSimplePolygon(line);
+*/
}
/*!
@@ -499,19 +524,19 @@ MAGICS_NO_EXPORT void BaseDriver::drizzle(const MFloat x, const MFloat y, const
MAGICS_NO_EXPORT void BaseDriver::lightning(const MFloat x, const MFloat y, const MFloat size) const
{
vector<PaperPoint> line;
- line.push_back(PaperPoint(x-(size*.3),y-(size)));
line.push_back(PaperPoint(x-(size*.3),y+(size)));
+ line.push_back(PaperPoint(x-(size*.3),y-(size)));
renderPolyline(line);
line.clear();
- line.push_back(PaperPoint(x-(size*.3),y-(size)));
- line.push_back(PaperPoint(x+(size*.3),y-(size)));
- line.push_back(PaperPoint(x,y));
+ line.push_back(PaperPoint(x-(size*.3),y+(size)));
line.push_back(PaperPoint(x+(size*.3),y+(size)));
+ line.push_back(PaperPoint(x,y));
+ line.push_back(PaperPoint(x+(size*.3),y-(size)));
renderPolyline(line);
line.clear();
- line.push_back(PaperPoint(x+(size*.35), y+(size*.3) ));
- line.push_back(PaperPoint(x+(size*.3), y+(size) ));
- line.push_back(PaperPoint(x, y+(size*.7)));
+ line.push_back(PaperPoint(x+(size*.35),y-(size*.3) ));
+ line.push_back(PaperPoint(x+(size*.3), y-(size) ));
+ line.push_back(PaperPoint(x, y-(size*.7)));
renderPolyline(line);
}
diff --git a/src/drivers/BaseDriverWind.h b/src/drivers/BaseDriverWind.h
index 8f70a3d..dbedb79 100644
--- a/src/drivers/BaseDriverWind.h
+++ b/src/drivers/BaseDriverWind.h
@@ -101,23 +101,26 @@ MAGICS_NO_EXPORT void BaseDriver::renderWindArrow(const Arrow &arrow) const
// if(fabs(norm) < 0.01) norm = scaling;
const double norm2 = norm * base;
-
+ double xx=0.;
vector<PaperPoint> line;
- (pos==M_TAIL) ? line.push_back(PaperPoint(0.,0.)) : line.push_back(PaperPoint( -0.5*norm,0.));
- double xx = (pos==M_TAIL) ? norm : 0.5 * norm;
- if((index==2) || (index==1)) xx = (pos==M_TAIL) ? norm2 : (base-0.5) * norm;
- line.push_back(PaperPoint(xx,0));
- for_each(line.begin(),line.end(),rotate(angle,ratio) );
- for_each(line.begin(),line.end(),translate(arr->point_) );
+ if(pos!=M_HEAD_ONLY)
+ {
+ (pos==M_TAIL) ? line.push_back(PaperPoint(0.,0.)) : line.push_back(PaperPoint( -0.5*norm,0.));
+ xx = (pos==M_TAIL) ? norm : 0.5 * norm;
+ if((index==2) || (index==1)) xx = (pos==M_TAIL) ? norm2 : (base-0.5) * norm;
- xx = (pos==M_TAIL) ? norm : 0.5*(norm); // reset length
+ line.push_back(PaperPoint(xx,0));
+ for_each(line.begin(),line.end(),rotate(angle,ratio) );
+ for_each(line.begin(),line.end(),translate(arr->point_) );
+ xx = (pos==M_TAIL) ? norm : 0.5*(norm); // reset length
- // Arrow base
- const int old_currentColourIndex = currentLineStyle_;
- currentLineStyle_ = setLineParameters(style,thickness);
- renderPolyline2(line);
- currentLineStyle_ = old_currentColourIndex;
+ // Arrow base
+ const int old_currentColourIndex = currentLineStyle_;
+ currentLineStyle_ = setLineParameters(style,thickness);
+ renderPolyline2(line);
+ currentLineStyle_ = old_currentColourIndex;
+ }
// Arrow head
const MFloat bx = (1.0-base) * norm; // a third of the length of arrow
@@ -129,9 +132,9 @@ MAGICS_NO_EXPORT void BaseDriver::renderWindArrow(const Arrow &arrow) const
index = 0;
}
+ line.clear();
if(index == 0)
{
- line.clear();
line.push_back(PaperPoint(xx-bx,-by));
line.push_back(PaperPoint(xx,0. ));
line.push_back(PaperPoint(xx-bx,by));
@@ -141,7 +144,6 @@ MAGICS_NO_EXPORT void BaseDriver::renderWindArrow(const Arrow &arrow) const
}
else
{
- line.clear();
line.push_back(PaperPoint(xx,0.));
line.push_back(PaperPoint(xx-bx,-by));
line.push_back(PaperPoint(xx-bx, by));
diff --git a/src/drivers/BinaryDriver.cc b/src/drivers/BinaryDriver.cc
index 7d6683d..ea4b3eb 100644
--- a/src/drivers/BinaryDriver.cc
+++ b/src/drivers/BinaryDriver.cc
@@ -524,7 +524,7 @@ MAGICS_NO_EXPORT void BinaryDriver::renderText(const Text& text) const
out_.write((char *)(&s),sizeof(int));
MagFont magfont = (*niceText).font();
- Colour colour = magfont.colour();
+ const Colour& colour = magfont.colour();
const MFloat r=colour.red();
const MFloat g=colour.green();
const MFloat b=colour.blue();
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt
index 7d9b9c6..70eddc6 100644
--- a/src/drivers/CMakeLists.txt
+++ b/src/drivers/CMakeLists.txt
@@ -1,88 +1,82 @@
-list( APPEND _drivers_srcs
+list( APPEND _drivers_srcs
# basic
-
BaseDriver.h BinaryDriver.h PostScriptDriver.h DriverManager.h
System.h BaseDriverImages.h BaseDriverWind.h BaseDriverSymbols.h
BaseDriver.cc DriverManager.cc BinaryDriver.cc PostScriptDriver.cc
-
+ KMLDriver.h KMLDriver.cc
+ GeoJsonDriver.h GeoJsonDriver.cc
+ SVGDriver.h SVGDriver.cc
# minizip
minizip/ioapi.c minizip/zip.c
minizip/ioapi.h minizip/zip.h minizip/crypt.h
-
+# libimagequant
+ libimagequant/blur.h libimagequant/libimagequant.c libimagequant/mediancut.c
+ libimagequant/mempool.c libimagequant/nearest.c libimagequant/pam.c
+ libimagequant/viter.c libimagequant/blur.c libimagequant/libimagequant.h
+ libimagequant/mediancut.h libimagequant/mempool.h libimagequant/nearest.h libimagequant/pam.h libimagequant/viter.h
+ libimagequant/rwpng.c libimagequant/rwpng.h
+ libimagequant/pngquant.c libimagequant/pngquant.h
)
if( MAGICS_QT )
- list( APPEND _drivers_srcs
- QtDriver.h
- MgQ/MgQ.h
+ list( APPEND _drivers_srcs
+ QtDriver.h QtDriver.cc
+ MgQ/MgQ.h
MgQ/MgQLayoutItem.h MgQ/MgQStepItem.h
- MgQ/MgQLayerItem.h MgQ/MgQPlotScene.h
- MgQ/MgQSymbol.h MgQ/MgQPixmapItem.h MgQ/MgQPathItem.h
- MgQ/MgQTextItem.h MgQ/MgQDriverObject.h
- MgQ/MgQPolylineSetItem.h MgQ/MgQScene.h MgQ/MgQSceneItem.h
- MgQ/MgQSceneCacheItem.h MgQ/MgQStepMetaData.h
- MgQ/MgQPattern.h MgQ/MgQHistoItem.h MgQ/MgQRootItem.h
- QtDriver.cc
+ MgQ/MgQLayerItem.h MgQ/MgQPlotScene.h
+ MgQ/MgQSymbol.h MgQ/MgQPixmapItem.h MgQ/MgQPathItem.h
+ MgQ/MgQTextItem.h MgQ/MgQDriverObject.h
+ MgQ/MgQPolylineSetItem.h MgQ/MgQScene.h MgQ/MgQSceneItem.h
+ MgQ/MgQSceneCacheItem.h MgQ/MgQStepMetaData.h
+ MgQ/MgQPattern.h MgQ/MgQHistoItem.h MgQ/MgQRootItem.h
MgQ/MgQPlotScene.cc
- MgQ/MgQLayoutItem.cc MgQ/MgQStepItem.cc
- MgQ/MgQLayerItem.cc
- MgQ/MgQSymbol.cc MgQ/MgQPixmapItem.cc MgQ/MgQPathItem.cc
- MgQ/MgQTextItem.cc
- MgQ/MgQPolylineSetItem.cc MgQ/MgQScene.cc MgQ/MgQSceneItem.cc
- MgQ/MgQSceneCacheItem.cc MgQ/MgQStepMetaData.cc
+ MgQ/MgQLayoutItem.cc MgQ/MgQStepItem.cc
+ MgQ/MgQLayerItem.cc
+ MgQ/MgQSymbol.cc MgQ/MgQPixmapItem.cc MgQ/MgQPathItem.cc
+ MgQ/MgQTextItem.cc
+ MgQ/MgQPolylineSetItem.cc MgQ/MgQScene.cc MgQ/MgQSceneItem.cc
+ MgQ/MgQSceneCacheItem.cc MgQ/MgQStepMetaData.cc
MgQ/MgQPattern.cc MgQ/MgQHistoItem.cc
- )
-
-
-
+ )
set (qt_files_HEADERS MgQ/MgQPlotScene.h)
- QT4_WRAP_CPP(qt_files_HEADERS_MOC ${qt_files_HEADERS})
-
+ if( MAGICS_QT5 )
+ QT5_WRAP_CPP(qt_files_HEADERS_MOC ${qt_files_HEADERS})
+ else()
+ QT4_WRAP_CPP(qt_files_HEADERS_MOC ${qt_files_HEADERS})
+ endif()
list( APPEND qt_srcs ${qt_files_HEADERS_MOC})
-
endif()
-if( MAGICS_CAIRO )
+if( HAVE_CAIRO )
list( APPEND _drivers_srcs CairoDriver.h CairoDriver.cc )
endif()
-if ( ENABLE_METVIEW )
- list (APPEND metview_include
- drivers/DriverManager.h
- drivers/BaseDriver.h
- ${CMAKE_CURRENT_BINARY_DIR}/../params/BaseDriverAttributes.h
- drivers/MgQ/MgQPlotScene.h
- drivers/MgQ/MgQScene.h
- drivers/QtDriver.h
- drivers/MgQ/MgQLayoutItem.h
- drivers/MgQ/MgQ.h
- drivers/MgQ/MgQSceneItem.h
- drivers/MgQ/MgQLayerItem.h
- drivers/MgQ/MgQRootItem.h
- drivers/MgQ/MgQStepMetaData.h
- )
- set( metview_include ${metview_include} PARENT_SCOPE )
+if ( HAVE_METVIEW )
+ list (APPEND metview_include
+ drivers/DriverManager.h
+ drivers/BaseDriver.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../params/BaseDriverAttributes.h
+ drivers/MgQ/MgQPlotScene.h
+ drivers/MgQ/MgQScene.h
+ drivers/QtDriver.h
+ drivers/MgQ/MgQLayoutItem.h
+ drivers/MgQ/MgQ.h
+ drivers/MgQ/MgQSceneItem.h
+ drivers/MgQ/MgQLayerItem.h
+ drivers/MgQ/MgQRootItem.h
+ drivers/MgQ/MgQStepMetaData.h
+ )
+ set( metview_include ${metview_include} PARENT_SCOPE )
endif()
-# if( MAGICS_MING )
-# list( APPEND mgq_srcs MingDriver.h MingDriver.cc )
-# endif()
-
-# KML
-list( APPEND _drivers_srcs KMLDriver.h KMLDriver.cc )
-
-# SVG
-list( APPEND _drivers_srcs SVGDriver.h SVGDriver.cc )
if( MAGICS_RASTER )
- list( APPEND mgq_srcs GDDriver.h GDDriver.cc )
+ list( APPEND _drivers_srcs GDDriver.h GDDriver.cc )
endif()
-# AM_CPPFLAGS = -DNO_ADDFILEINEXISTINGZIP -I$(top_srcdir)/src -I$(top_srcdir)/src/terralib/kernel -I$(top_srcdir)/src/basic -I$(top_srcdir)/src/drivers -I$(top_srcdir)/src/drivers -I$(top_srcdir)/src/decoders -I$(top_srcdir)/src/visualisers
-
foreach( file ${_drivers_srcs} )
list( APPEND drivers_srcs drivers/${file} )
endforeach()
+set( CMAKE_C_FLAGS "-std=c99 -DNO_ADDFILEINEXISTINGZIP")
set( drivers_srcs ${drivers_srcs} PARENT_SCOPE )
-
diff --git a/src/drivers/CairoDriver.cc b/src/drivers/CairoDriver.cc
index fef14bf..881f59a 100644
--- a/src/drivers/CairoDriver.cc
+++ b/src/drivers/CairoDriver.cc
@@ -14,6 +14,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+European Centre for Medium-Range Weather Forecasts
******************************** LICENSE ********************************/
@@ -72,13 +73,19 @@ Something like:
#include <cairo-svg.h>
#endif
+/*
#if CAIRO_HAS_XLIB_SURFACE
#include <cairo-xlib.h>
Display *dpy;
#endif
+*/
#define FONT_SCALE 25*.7 //! \todo clean-up!!!
+extern "C"{
+#include "libimagequant/pngquant.h"
+}
+
using namespace magics;
/*!
@@ -214,6 +221,7 @@ void CairoDriver::setupNewSurface() const
MagLog::error() << "CairoDriver: SVG output NOT supported! Enable SVG support in your Cairo installation." << std::endl;
#endif
}
+/*
else if(magCompare(backend_,"x"))
{
#if CAIRO_HAS_XLIB_SURFACE
@@ -241,6 +249,7 @@ void CairoDriver::setupNewSurface() const
MagLog::error() << "CairoDriver: Xlib output NOT supported! Enable Xlib support in your Cairo installation." << std::endl;
#endif
}
+*/
else
{
MagLog::error() << "CairoDriver: The backend "<< backend_ <<" is NOT supported!" << std::endl;
@@ -290,9 +299,9 @@ void CairoDriver::setupNewSurface() const
#endif
}
-#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 2, 0)
- cairo_surface_set_fallback_resolution (surface_, resolution_, resolution_);
-#endif
+//#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 2, 0)
+// cairo_surface_set_fallback_resolution (surface_, resolution_, resolution_);
+//#endif
if(magCompare(transparent_,"off") || !(magCompare(backend_,"png") || magCompare(backend_,"geotiff")) )
{
cairo_set_source_rgb (cr_, 1.0, 1.0, 1.0); /* white */
@@ -334,6 +343,7 @@ void CairoDriver::close()
cairo_surface_destroy (surface_);
cairo_destroy (cr_);
}
+/*
#if CAIRO_HAS_XLIB_SURFACE
if(magCompare(backend_,"x"))
{
@@ -348,6 +358,7 @@ void CairoDriver::close()
XCloseDisplay(dpy);
}
#endif
+*/
}
@@ -438,14 +449,24 @@ MAGICS_NO_EXPORT void CairoDriver::endPage() const
else if (magCompare(backend_,"png") )
{
Timer timer("cairo", "write png");
-// write_png(surface_, "test256.png");
filename_ = getFileName("png" ,currentPage_);
- cairo_surface_write_to_png(surface_, filename_.c_str());
+ if(magCompare(palette_,"on"))
+ {
+ if(!write_8bit_png())
+ {
+ MagLog::warning() << "CairoDriver::renderPNG > palletted PNG failed! Generate 24 bit one ..." << endl;
+ cairo_surface_write_to_png(surface_, filename_.c_str());
+ }
+ }
+ else
+ {
+ cairo_surface_write_to_png(surface_, filename_.c_str());
+ }
if(!filename_.empty()) printOutputName("CAIRO png "+filename_);
}
else if (magCompare(backend_,"geotiff") )
{
-#ifdef MAGICS_GEOTIFF
+#ifdef HAVE_GEOTIFF
filename_ = getFileName("tif" ,currentPage_);
write_tiff();
#else
@@ -454,7 +475,7 @@ MAGICS_NO_EXPORT void CairoDriver::endPage() const
}
}
-#ifdef MAGICS_GEOTIFF
+#ifdef HAVE_GEOTIFF
#include <geotiffio.h>
#include <tiffio.h>
@@ -479,14 +500,14 @@ MAGICS_NO_EXPORT void CairoDriver::write_tiff() const
TIFF *tif = TIFFOpen(filename_.c_str(), "w");
if (!tif) {
- MagLog::warning() << "CairoDriver: Unable to open TIFF file "<<filename_.c_str()<< std::endl;
+ MagLog::warning() << "CairoDriver: Unable to open TIFF file "<<filename_<< std::endl;
return;
}
GTIF *gtif = GTIFNew(tif);
if (!gtif)
{
- MagLog::warning() << "CairoDriver: Unable to open GeoTIFF file "<<filename_.c_str()<< std::endl;
+ MagLog::warning() << "CairoDriver: Unable to open GeoTIFF file "<<filename_<< std::endl;
return;
}
@@ -542,7 +563,151 @@ MAGICS_NO_EXPORT void CairoDriver::write_tiff() const
_TIFFfree(buf);
return;
}
-#endif // MAGICS_GEOTIFF
+#endif // HAVE_GEOTIFF
+
+#include <png.h>
+/*!
+ \brief write raster into 8 bit PNG
+
+ Only the raw raster (normally written to a 32 bit PNG) is here written into a 8 bit.
+
+*/
+//#define PNG_DEBUG 3
+
+MAGICS_NO_EXPORT bool CairoDriver::write_8bit_png() const
+{
+ cairo_surface_flush (surface_);
+ unsigned char *data = cairo_image_surface_get_data(surface_);
+ const int width = cairo_image_surface_get_width(surface_);
+ const int height = cairo_image_surface_get_height(surface_);
+
+ struct pngquant_options options_ = { };
+ options_.liq = liq_attr_create();
+ struct pngquant_options *options = &options_;
+ // pngquant_file(filename_.c_str(), filename.c_str(), &options);
+
+ pngquant_error retval = SUCCESS;
+ liq_image* input_image = NULL;
+
+ unsigned char *data2 = new unsigned char[4*width*height];
+ for(int h=0; h<height; h++)
+ {
+ for(int w=0; w<(width*4); w=w+4)
+ {
+ data2[h*4*width+w ] = data[h*4*width+w+2]; // r
+ data2[h*4*width+w+1] = data[h*4*width+w+1]; // g
+ data2[h*4*width+w+2] = data[h*4*width+w ]; // b
+ data2[h*4*width+w+3] = data[h*4*width+w+3]; // a
+ }
+ }
+
+ input_image = liq_image_create_rgba(options->liq, data2, width, height, 0);
+ if (!input_image) {
+ //return OUT_OF_MEMORY_ERROR;
+ }
+
+ int quality_percent = 90; // quality on 0-100 scale, updated upon successful remap
+ png8_image output_image = {};
+
+ // when using image as source of a fixed palette the palette is extracted using regular quantization
+ liq_result *remap = liq_quantize_image(options->liq, options->fixed_palette_image ? options->fixed_palette_image : input_image);
+
+ if (remap) {
+ //liq_set_output_gamma(remap, 0.45455); // fixed gamma ~2.2 for the web. PNG can't store exact 1/2.2
+ liq_set_dithering_level(remap, options->floyd);
+
+ retval = prepare_output_image(remap, input_image, &output_image);
+ if (SUCCESS == retval) {
+ if (LIQ_OK != liq_write_remapped_image_rows(remap, input_image, output_image.row_pointers)) {
+ retval = OUT_OF_MEMORY_ERROR;
+ }
+
+ set_palette(remap, &output_image);
+
+ double palette_error = liq_get_quantization_error(remap);
+ if (palette_error >= 0) {
+ quality_percent = liq_get_quantization_quality(remap);
+ }
+ }
+ liq_result_destroy(remap);
+ } else {
+ retval = TOO_LOW_QUALITY;
+ }
+
+ if (SUCCESS == retval) {
+ output_image.fast_compression = false; // (fast_compression ? Z_BEST_SPEED : Z_BEST_COMPRESSION);
+
+ retval = write_image(&output_image, NULL, filename_.c_str(), options);
+ }
+
+ liq_image_destroy(input_image);
+ rwpng_free_image8(&output_image);
+
+ if (SUCCESS == retval) return true;
+ return false;
+}
+
+/*
+MAGICS_NO_EXPORT void CairoDriver::write_8bit_png() const
+{
+ const string filename = filename_ +"_8bit";
+ FILE * fp = fopen (filename.c_str(), "wb");
+ if (! fp) {
+ MagLog::error() << "CairoDriver: Unable to open 8 bit PNG file "<<filename<< std::endl;
+ return;
+ }
+
+ cairo_surface_flush (surface_);
+ unsigned char *data = cairo_image_surface_get_data(surface_);
+ int width = cairo_image_surface_get_width(surface_);
+ int height = cairo_image_surface_get_height(surface_);
+// const int stride = cairo_image_surface_get_stride(surface_);
+ const int depth = 8;
+
+ png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if(!png_ptr)
+ {
+ MagLog::error() << "CairoDriver: Unable to create WRITE struct for 8 bit PNG file "<<filename<< std::endl;
+ return;
+ }
+
+ png_infop info_ptr = png_create_info_struct (png_ptr);
+ if(!png_ptr)
+ {
+ MagLog::error() << "CairoDriver: Unable to create INFO struct for 8 bit PNG file "<<filename<< std::endl;
+ return;
+ }
+// setjmp (png_jmpbuf (png_ptr));
+
+ // Set image attributes
+ png_set_IHDR (png_ptr,
+ info_ptr,
+ width,
+ height,
+ depth,
+ PNG_COLOR_TYPE_RGBA,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ // Initialize rows of PNG.
+ png_bytep *row_pointers = (png_bytep*) malloc(3 * width * sizeof(png_byte));
+
+ for (size_t y = 0; y < height; ++y) {
+ row_pointers[y] = data + width * 4 * y;
+ }
+
+ // Write the image data to file
+ png_init_io (png_ptr, fp);
+ png_set_rows (png_ptr, info_ptr, row_pointers);
+ png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);
+
+ // free (row_pointers);
+ // png_destroy_write_struct (&png_ptr, &info_ptr);
+ fclose (fp);
+ return;
+}
+*/
/*!
\brief project to a new Layout
@@ -581,22 +746,15 @@ MAGICS_NO_EXPORT void CairoDriver::project(const Layout& layout) const
offsetX_ = projectX( -layout.minX());
offsetY_ = projectY( -layout.minY() );
-/*
- if(box->getClip())
+
+ if(layout.clipp())
{
// cairo_set_source_rgb(cr_, 1,0,0);
- cairo_rectangle (cr_, projectX(Xmin),projectY(Ymin),projectX(Xmax)-projectX(Xmin),projectY(Ymax)-projectY(Ymin) );
+ cairo_rectangle (cr_, projectX(layout.minX()),projectY(layout.minY()),projectX(layout.maxX())-projectX(layout.minX()),projectY(layout.maxY())-projectY(layout.minY()) );
cairo_clip(cr_);
// cairo_stroke(cr_);
}
- if(box->centered())
- {
- Xoff += Xlength*0.5;
- Yoff += Ylength*0.5;
- obsBox_=true;
- }
- else obsBox_=false;
-*/
+
// write meta info
if(layout.isNavigable() && (magCompare(backend_,"png") || magCompare(backend_,"svg") || magCompare(backend_,"geotiff")) )
{
@@ -985,8 +1143,7 @@ MAGICS_NO_EXPORT void CairoDriver::renderSimplePolygon() const
<< " Solid shading used instead."<< std::endl;
#endif
{
- if(cairo_get_antialias(cr_) != CAIRO_ANTIALIAS_NONE && currentColour_.alpha() > 0.9999 )
-
+/* if(cairo_get_antialias(cr_) != CAIRO_ANTIALIAS_NONE && currentColour_.alpha() > 0.9999 )
//if(magCompare(backend_,"png")) // if(cairo_get_antialias(cr_) != CAIRO_ANTIALIAS_NONE && currentColour_.alpha() > 0.9999 )
{
cairo_fill_preserve(cr_);
@@ -994,6 +1151,7 @@ MAGICS_NO_EXPORT void CairoDriver::renderSimplePolygon() const
cairo_stroke(cr_);
}
else
+*/
{
cairo_fill(cr_);
}
@@ -1169,24 +1327,24 @@ MAGICS_NO_EXPORT void CairoDriver::circle(const MFloat x, const MFloat y, const
int fill = s;
- if(s > 8) fill = 8;
- if(s > 0)
+ //if(s > 8) fill = 8;
+ if( (s > 0) && (fill != 9) )
{
cairo_arc (cr_, xx, yy, r, -M_PI * .5, M_PI * ((0.25 * fill)-.5) );
+ cairo_line_to (cr_, xx, yy);
cairo_fill(cr_);
}
if(fill == 9)
{
- cairo_set_source_rgb(cr_,1,1,1);
- cairo_move_to (cr_, xx, yy+r-1);
- cairo_line_to (cr_, xx, yy-r+1);
- cairo_stroke(cr_);
- cairo_set_source_rgba(cr_,currentColour_.red(),currentColour_.green(),currentColour_.blue(),currentColour_.alpha());
+ cairo_arc (cr_, xx-0.5, yy, r, M_PI * .5, -M_PI * .5 );
+ cairo_fill(cr_);
+ cairo_arc (cr_, xx+0.5, yy, r, -M_PI * .5, M_PI * .5 );
+ cairo_fill(cr_);
}
cairo_arc (cr_, xx, yy, r, 0., M_PI * 2.);
- cairo_stroke(cr_);
+ cairo_stroke(cr_);
cairo_restore(cr_);
#else
MagLog::warning() << "CairoDriver::circle requires at least cairo version 1.2!" << endl;
@@ -1359,7 +1517,7 @@ MAGICS_NO_EXPORT bool CairoDriver::renderCellArray(const Image& image) const
}
else
{
- const double al = tr;//lt[c].alpha();
+ const double al = lt[c].alpha();
chImage[jj]=char(int(255.*cb *al )); jj++;
chImage[jj]=char(int(255.*cg *al )); jj++;
chImage[jj]=char(int(255.*cr *al )); jj++;
diff --git a/src/drivers/CairoDriver.h b/src/drivers/CairoDriver.h
index 4ed28db..db11c9d 100644
--- a/src/drivers/CairoDriver.h
+++ b/src/drivers/CairoDriver.h
@@ -65,7 +65,7 @@ public:
magCompare(node.name(), "pdf") ||
magCompare(node.name(), "cairo_ps") ||
magCompare(node.name(), "cairo_svg") ||
- magCompare(node.name(), "x") ||
+ // magCompare(node.name(), "x") ||
magCompare(node.name(), "cairo_eps") ||
magCompare(node.name(), "geotiff") )
{
@@ -91,7 +91,7 @@ public:
void setPS () const {backend_ = "ps";}
void setEPS() const {backend_ = "eps";}
void setSVG() const {backend_ = "svg";}
- void setX() const {backend_ = "x";}
+// void setX() const {backend_ = "x";}
void setGEOTIFF() const {backend_ = "geotiff";}
void setCairo() const {backend_ = "cairo";}
@@ -137,9 +137,10 @@ private:
MAGICS_NO_EXPORT MFloat setSymbolY(const MFloat y) const {return -y;}
MAGICS_NO_EXPORT MFloat setFlagY(const MFloat y) const {return -y;}
MAGICS_NO_EXPORT MFloat setY(const MFloat y) const {return y;}
-#ifdef MAGICS_GEOTIFF
+#ifdef HAVE_GEOTIFF
MAGICS_NO_EXPORT void write_tiff() const;
#endif
+ MAGICS_NO_EXPORT bool write_8bit_png() const;
mutable MFloat offsetX_;
mutable MFloat offsetY_;
mutable stack<MFloat> offsetsX_;
diff --git a/src/drivers/GeoJsonDriver.cc b/src/drivers/GeoJsonDriver.cc
new file mode 100755
index 0000000..f22bf59
--- /dev/null
+++ b/src/drivers/GeoJsonDriver.cc
@@ -0,0 +1,654 @@
+/******************************** LICENSE ********************************
+
+
+ Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ ******************************** LICENSE ********************************/
+
+/*! \file GeoJsonDriver.cc
+ \brief Implementation of GeoJsonDriver.
+ \author Meteorological Visualisation Section, ECMWF
+
+ Started: Thu Jun 09 18:41:52 2015
+
+*/
+
+#include <GeoJsonDriver.h>
+#include <Polyline.h>
+#include <Text.h>
+#include <Image.h>
+#include <Symbol.h>
+#include <Layer.h>
+#include <Arrow.h>
+#include <Flag.h>
+
+
+//! For generating ZIP files
+extern "C"{
+#include <sys/stat.h>
+#include "minizip/zip.h"
+#define MAXFILENAME 256
+#define WRITEBUFFERSIZE 16384
+#include <cstdio> // BUFSIZ
+#include <fcntl.h> // open
+#include <unistd.h>
+}
+
+
+using namespace magics;
+
+
+/*!
+ \brief Constructor
+*/
+GeoJsonDriver::GeoJsonDriver() : currentTimeBegin_(""),currentTimeEnd_(""),GeoJson_placemark_(false),
+ polyline_begin_(true),polygon_begin_(true),MultiGeometrySet_(false),layer_(false),
+ render_(true),ecmwf_logo_(false)
+{
+}
+
+/*!
+ \brief Destructor
+*/
+GeoJsonDriver::~GeoJsonDriver()
+{
+}
+
+/*!
+ \brief Opening the driver
+*/
+void GeoJsonDriver::open()
+{
+ currentPage_ = 0;
+
+ fileName_ = getFileName("json");
+ if(zip_) fileName_ = "doc.json";
+
+ pFile_.open(fileName_.c_str());
+ if(!pFile_)
+ {
+ MagLog::error() << "GeoJsonDriver::open() --> Cannot open GeoJson output file: " << fileName_ << "!\n";
+ MagLog::error() << ""; // to ensure that the error message is broadcast
+ terminate();
+ }
+/* pFile_ << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ << "<GeoJson xmlns=\"http://www.opengis.net/GeoJson/2.2\" \n"
+ << " xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"
+ << "<Document>\n"<< " <name>"<<title_<<"</name>\n"
+ << " <open>1</open>\n";
+ pFile_ << " <atom:generator>"<<getMagicsVersionString()<<"</atom:generator>\n";
+ if(!author_.empty()) pFile_ << " <atom:author><atom:name>"<<author_<<"</atom:name></atom:author>\n";
+ if(!link_.empty()) pFile_ << " <atom:link href=\""<<link_<<"\" />\n";
+ pFile_ << " <description>\n"
+ << " <![CDATA["<<description_<<"]]>\n"
+ << " </description>\n"
+ << " <LookAt>\n"
+ << "\t<longitude>"<<longitude_<<"</longitude>\n"
+ << "\t<latitude>"<<latitude_<<"</latitude>\n"
+ << "\t<range>"<<range_*1000.<<"</range>\n"
+ << "\t<tilt>"<<tilt_<<"</tilt>\n"
+ << "\t<heading>0</heading>\n" // always 0 = north!
+ << "\t<altitudeMode>absolute</altitudeMode>\n" // possibly "relativeToGround"
+ << " </LookAt>\n"
+ << " <Style id=\"check-hide-children\">\n"
+ << " <ListStyle>\n"
+ << " <listItemType>checkHideChildren</listItemType>\n"
+ << " </ListStyle>\n"
+ << " </Style>\n";
+ */
+ GeoJson_placemark_=false;
+}
+
+/*!
+ \brief Closing the driver
+
+ While closing the driver all files generated (stored in GeoJson_output_resource_list_ )
+ are put into one zip file. We use minizip (see minizip subdirectory to
+ do so) since gnuzip is NOT sufficient!
+*/
+void GeoJsonDriver::close()
+{
+ if (GeoJson_placemark_) closePlacemark();
+
+// pFile_ << "</Document>\n</GeoJson>\n";
+ pFile_.close();
+ GeoJson_output_resource_list_.push_back(fileName_);
+
+ /*********************** K M Z ********************************/
+ if(zip_ && !GeoJson_output_resource_list_.empty())
+ {
+ fileName_ = getFileName("zip");
+ zipFile zf;
+ int err=0;
+
+ zf = zipOpen(fileName_.c_str(),0);
+ if (zf == 0)
+ {
+ printf("ERROR opening zip file %s\n",fileName_.c_str());
+ }
+ else
+ {
+ int size_buf = WRITEBUFFERSIZE;
+ void* buf = (void*)malloc(size_buf);
+ if (buf==0)
+ {
+ MagLog::error() <<"Error allocating memory for GeoJson ZIP generation!"<< std::endl;
+ return;
+ }
+ stringarray::iterator it = GeoJson_output_resource_list_.begin();
+ stringarray::iterator itend = GeoJson_output_resource_list_.end();
+ for(; it != itend; it++)
+ {
+ if(debug_) MagLog::dev()<< "GeoJsonDriver.close() > Start adding file " << *it << " to ZIP file.\n";
+ FILE * fin;
+ int size_read;
+
+ const char *filename = (*it).c_str();
+
+ err = zipOpenNewFileInZip(zf,filename, 0, 0, 0, 0, 0, 0, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
+
+ if(err != ZIP_OK)
+ MagLog::error() << "Could NOT open ZIP file "<< filename << endl;
+ else
+ {
+ fin = fopen(filename,"rb");
+ if(fin==0)
+ {
+ MagLog::error() << "Open file "<<filename<<" to be added to ZIP FAILED!"<< endl;
+ return;
+ }
+ else
+ {
+ do{
+ err=ZIP_OK;
+ size_read = (int)fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ MagLog::error() << "Could NOT add "<<(*it) << endl;
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ {
+ err = zipWriteInFileInZip(zf,buf,size_read);
+ if (err<0)
+ {
+ MagLog::error() << "Could NOT write ZIP file "<< fileName_<< endl;
+ }
+ }
+ } while ((err==ZIP_OK) && (size_read>0));
+ }
+ if (fin)
+ fclose(fin);
+ }
+
+ err = zipCloseFileInZip(zf);
+ if (err!=ZIP_OK)
+ MagLog::error() << "Could NOT close ZIP file "<< fileName_<< endl;
+// delete [] filename;
+ }
+ free(buf);
+
+ err = zipClose(zf,0);
+ if (err != ZIP_OK)
+ MagLog::error() << "Could NOT close ZIP file "<< fileName_<< endl;
+ else if (!debug_)
+ {
+ stringarray::iterator it = GeoJson_output_resource_list_.begin();
+ stringarray::iterator itend = GeoJson_output_resource_list_.end();
+ for(; it != itend; it++)
+ {
+ remove((*it).c_str());
+ }
+ }
+ printOutputName("GeoJson zip "+fileName_);
+ }// end Zipping ---> K M Z
+ }
+ else if(!zip_)
+ {
+ stringarray::iterator it = GeoJson_output_resource_list_.begin();
+ stringarray::iterator itend = GeoJson_output_resource_list_.end();
+ for(; it != itend; it++)
+ {
+ printOutputName("GeoJson misc "+(*it));
+ }
+ }
+}
+
+/*!
+ \brief starting a new page
+
+ This method has to take care that previous pages are closed and that
+ for formats with multiple output files a new file is set up.
+
+ \note There is NO page concept in GeoJson!
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::startPage() const
+{
+ currentPage_++;
+
+ debugOutput("Start Page");
+
+ polyline_begin_ = true;
+ polygon_begin_ = true;
+ currentLayer_ = "Page";
+ newLayer();
+}
+
+/*!
+ \brief ending a page
+
+ This method has to take care that for formats with multiple output
+ files are closed.
+
+ \note There is NO page concept in GeoJson!
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::endPage() const
+{
+ if (GeoJson_placemark_) closePlacemark();
+ closeLayer();
+ debugOutput("Close page");
+}
+
+/*!
+ \brief project to a new Layout
+
+ This method will update the offset and scale according to the new Layout given.
+
+ \sa Layout
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::project(const magics::Layout& layout) const
+{
+//MagLog::dev() << " GeoJsonDriver::project("<<layout.id()<<")"<< endl;
+}
+
+MAGICS_NO_EXPORT void GeoJsonDriver::redisplay(const magics::LegendLayout& layout) const
+{
+ MagLog::warning() << " GeoJsonDriver> legend could NOT be generated!"<< endl;
+}
+
+/*!
+ \brief setup a new layer
+
+ This method will setup a new layer. Layers enable overlays of entities
+ of information.
+
+ \sa Layer
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::redisplay(const StaticLayer& layer) const
+{
+ currentLayer_ = (layer.name().empty()) ? "StaticLayer" : layer.name();
+ currentTimeBegin_ = layer.timeBegin();
+ currentTimeEnd_ = layer.timeEnd();
+ currentTimeStamp_ = layer.timeStamp();
+ newLayer();
+ layer.visit(*this);
+ closeLayer();
+}
+
+MAGICS_NO_EXPORT void GeoJsonDriver::redisplay(const StepLayer& layer) const
+{
+ currentLayer_ = (layer.name().empty()) ? "Step" : layer.name();
+ currentTimeBegin_ = layer.timeBegin();
+ currentTimeEnd_ = layer.timeEnd();
+ currentTimeStamp_ = layer.timeStamp();
+ newLayer();
+ layer.visit(*this);
+ closeLayer();
+}
+
+MAGICS_NO_EXPORT void GeoJsonDriver::redisplay(const SceneLayer& layer) const
+{
+ currentLayer_ = (layer.name().empty()) ? "Scene" : layer.name();
+// currentTimeBegin_ = layer.timeBegin();
+// currentTimeEnd_ = layer.timeEnd();
+// currentTimeStamp_ = layer.timeStamp();
+ newLayer();
+ layer.visit(*this);
+ closeLayer();
+}
+
+/*!
+ \brief gets ignored in GeoJson
+
+ \sa BaseDriver::redisplay(const NoDataLayer&)
+ */
+MAGICS_NO_EXPORT void GeoJsonDriver::redisplay(const NoDataLayer& layer) const
+{
+ if( coastlines_ )
+ {
+ currentLayer_ = (layer.name().empty()) ? "NoData" : layer.name();
+ currentTimeBegin_ = layer.timeBegin();
+ currentTimeEnd_ = layer.timeEnd();
+ newLayer();
+ layer.visit(*this);
+ closeLayer();
+ }
+}
+
+/*!
+ \brief open new layer
+
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::newLayer() const
+{
+ if (GeoJson_placemark_) closePlacemark();
+
+ // cut off path (especially for Metview
+ unsigned found = currentLayer_.find_last_of("/\\");
+ currentLayer_=currentLayer_.substr(found+1);
+
+ debugOutput("Start Layer - "+currentLayer_);
+
+ polyline_begin_=true;
+ polygon_begin_=true;
+ layer_=true;
+ render_=true;
+}
+
+
+/*!
+ \brief close the current layer
+
+ This method will close an existing layer. This includes resets of existing boxes.
+
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::closeLayer() const
+{
+ if (GeoJson_placemark_) closePlacemark();
+
+ layer_=false;
+ render_=false;
+// pFile_ << "</Folder>\n";
+ debugOutput("Close Layer - "+currentLayer_);
+}
+
+
+MAGICS_NO_EXPORT void GeoJsonDriver::closePlacemark() const
+{
+}
+
+/*!
+ \brief sets a new colour
+
+ This colour stays the default drawing colour until the painting in the
+ current box is finished.
+
+ Expression is aabbggrr, where aa=alpha (00 to ff); bb=blue (00 to ff);
+ gg=green (00 to ff); rr=red (00 to ff)
+
+ \sa Colour
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::setNewColour(const Colour &colour) const
+{
+}
+
+MAGICS_NO_EXPORT void GeoJsonDriver::writeColour(const Colour &col) const
+{
+}
+
+/*!
+ \brief sets a new line width
+
+ This line width stays the default width until the painting in the
+ current box is finished.
+
+ \sa setLineParameters()
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::setNewLineWidth(const MFloat width) const
+{
+}
+
+/*!
+ \brief sets new properties of how lines are drawn
+
+ These properties stay the default until the painting in the
+ current box is finished.
+
+ \sa LineStyle
+
+ param linestyle Object describing the line style
+ param w width of the line
+
+*/
+MAGICS_NO_EXPORT int GeoJsonDriver::setLineParameters(const LineStyle , const MFloat w) const
+{
+ return 0;
+}
+
+/*!
+ \brief renders polylines
+
+ This method renders a polyline given as two MFloat arrays. The two
+ arrays given as X and Y values have to be at least the length of
+ <i>n</i>. All values beyond <i>n</i> will be ignored. The style is
+ determined by what is described in the current LineStyle.
+
+ \sa setLineParameters()
+ \param n number of points
+ \param x array of x values
+ \param y array of y values
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::renderPolyline(const int n, MFloat *x, MFloat *y) const
+{
+ pFile_ << "{\n \"coordinates\": [\n [\n";
+ for(int is=0;is<n;is++)
+ {
+ pFile_ <<" ["<< x[is]<<","<<y[is]<<"]";
+ if(is<n-1) pFile_ <<",\n";
+ else pFile_ <<"\n";
+ }
+ pFile_ << " ] ],\n \"properties\": {\n \"type\": \"cold fronts\"\n },\n \"type\": \"MultiLineString\"\n}"<<endl;
+}
+
+
+/*!
+ \brief renders a filled polygon
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::renderSimplePolygon(const int n, MFloat* xx, MFloat* yy) const
+{
+ if (!render_) return;
+ if (GeoJson_placemark_) closePlacemark();
+
+ pFile_ << "{\n \"coordinates\": [\n [\n";
+ for(int is=0;is<n;is++)
+ {
+ pFile_ <<" ["<< xx[is]<<","<<yy[is]<<"]";
+ if(is<n-1) pFile_ <<",\n";
+ else pFile_ <<"\n";
+ }
+ pFile_ << " ],\n \"properties\": {\n \"type\": \"cold fronts\"\n },\n \"type\": \"MultiLineString\"\n}"<<endl;
+}
+
+void GeoJsonDriver::renderSimplePolygon(const Polyline& line) const
+{
+ if (!render_) return;
+ if (GeoJson_placemark_) closePlacemark();
+ const unsigned int n = line.size();
+ if(n<3) return;
+
+ Colour tmpcol = currentColour_;
+ setNewColour(line.getFillColour());
+
+ MFloat *x = new MFloat[n];
+ MFloat *y = new MFloat[n];
+ for(unsigned int i=0;i<n;i++)
+ {
+ const PaperPoint& pp = line.get(i);
+ x[i] = pp.x();
+ y[i] = pp.y();
+ }
+
+ pFile_ << "{\n \"coordinates\": [\n [\n";
+ for(int is=0;is<n;is++)
+ {
+ pFile_ <<" ["<< x[is]<<","<<y[is]<<"]";
+ if(is<n-1) pFile_ <<",\n";
+ else pFile_ <<"\n";
+
+ }
+ pFile_ << " ],\n \"properties\": {\n \"type\": \"cold fronts\"\n },\n \"type\": \"MultiLineString\"\n}"<<endl;
+
+ delete [] x;
+ delete [] y;
+
+/*
+ Polyline::Holes::const_iterator h = line.beginHoles();
+ Polyline::Holes::const_iterator he = line.endHoles();
+
+ for (; h != he; ++h)
+ {
+ pFile_ << " <innerBoundaryIs>\n"
+ << " <LinearRing>\n"
+ << " <coordinates>\n";
+
+ vector<double> x;
+ vector<double> y;
+ line.hole(h,x,y);
+ if ( x.empty() )
+ continue;
+ vector<double>::const_iterator yt = y.begin();
+ vector<double>::const_iterator xt = x.begin();
+ for(int it=0;it<x.size();it++)
+ {
+ pFile_ <<"\t"<< x[it] <<","<< y[it] <<","<<height_*1000<<"\n";
+ }
+
+ pFile_ << " </coordinates>\n"
+ << " </LinearRing>\n"
+ << " </innerBoundaryIs>\n";
+ }
+ pFile_ << "</Polygon>\n";
+ pFile_ << "</MultiGeometry>\n</Placemark>";
+*/
+ setNewColour(tmpcol);
+}
+
+/*!
+ \brief renders text strings
+
+ This method renders given text strings.
+
+ \sa Text
+ \param text object containing the strings and their description
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::renderText(const Text& text) const
+{
+}
+
+
+
+/*!
+ \brief render pixmaps
+
+ This method renders pixmaps. These are used for cell shading and raster input (GIFs and PNGs).
+
+ \sa renderCellArray()
+
+ param x0 x of lower corner
+ param y0 y of lower corner
+ param x1 x of higher corner
+ param y1 y of higher corner
+ param w width of pixmap
+ param h height of pixmap
+ param pixmap contents
+
+*/
+MAGICS_NO_EXPORT bool GeoJsonDriver::renderPixmap(MFloat x0,MFloat y0,MFloat x1,MFloat y1,
+ int w,int h,unsigned char* pixmap,int, bool) const
+{
+ debugOutput("Start renderPixmap");
+ if(render_)
+ {
+ if (GeoJson_placemark_) closePlacemark();
+ MagLog::warning() << "Image import is not implemented for the used driver!!!" << endl; return false;
+ debugOutput("End renderPixmap");
+ return true;
+ }
+}
+
+/*!
+ \brief render cell arrays
+
+ This method renders cell arrays, also called images in Magics language. These are
+ mainly used for satellite data.
+
+ sa renderPixmap()
+
+ param image Object containing an image
+*/
+MAGICS_NO_EXPORT bool GeoJsonDriver::renderCellArray(const Image& image) const
+{
+ debugOutput("Start renderCellArray");
+ if(render_)
+ {
+ if (GeoJson_placemark_) closePlacemark();
+ MagLog::warning() << "Image import is not implemented for the used driver!!!" << endl; return false;
+ }
+ debugOutput("End renderCellArray");
+ return true;
+}
+
+
+//! Method to plot symbols
+/*!
+ Needs special treatment of MagLogo. The logo is added on close().
+
+ \sa close
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::renderSymbols(const Symbol& symbol) const
+{
+ if(symbol.getSymbol()=="logo_ecmwf")
+ ecmwf_logo_=true;
+// else
+// BaseDriver::renderSymbols(symbol);
+}
+
+
+MAGICS_NO_EXPORT void GeoJsonDriver::renderWindArrow(const Arrow &arrow) const
+{
+}
+
+
+MAGICS_NO_EXPORT void GeoJsonDriver::renderWindFlag(const Flag &flag) const
+{
+}
+
+
+/*!
+ \brief prints debug output
+
+ When Magics++ is compiled in debug mode these extra strings are printed.
+
+ \note This can increase file and log file sizes if you run Magics++ in debug mode!
+
+ \param s string to be printed
+*/
+MAGICS_NO_EXPORT void GeoJsonDriver::debugOutput(const string &s) const
+{
+}
+
+/*!
+ \brief class information are given to the output-stream
+*/
+void GeoJsonDriver::print(ostream& out) const
+{
+ out << "GeoJsonDriver[";
+ out << "]";
+}
+
+static SimpleObjectMaker<GeoJsonDriver, BaseDriver> GeoJson_driver("GeoJson");
diff --git a/src/drivers/GeoJsonDriver.h b/src/drivers/GeoJsonDriver.h
new file mode 100755
index 0000000..80051b6
--- /dev/null
+++ b/src/drivers/GeoJsonDriver.h
@@ -0,0 +1,142 @@
+/******************************** LICENSE ********************************
+
+
+ Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ ******************************** LICENSE ********************************/
+
+/*!
+ \file GeoJsonDriver.h
+ \brief Definition of GeoJsonDriver.
+ \author Meteorological Visualisation Section, ECMWF
+
+ Started: Thu Jun 09 18:41:52 2015
+*/
+
+#ifndef _GeoJsonDriver_H
+#define _GeoJsonDriver_H
+
+#include <BaseDriver.h>
+#include <GeoJsonDriverAttributes.h>
+#include <XmlNode.h>
+
+namespace magics
+{
+
+/*! \class GeoJsonDriver
+ \brief This driver produces output for GeoJson
+ \ingroup drivers
+
+ The driver produces Keyhole XML (GeoJson) output for usage with
+ Google Earth (http://earth.google.com/) and Google Maps (http://maps.google.com/).
+*/
+class GeoJsonDriver: public BaseDriver, public GeoJsonDriverAttributes
+{
+
+public:
+ GeoJsonDriver();
+ ~GeoJsonDriver();
+ void open();
+ void close();
+
+ /*!
+ \brief sets a new XML node
+ */
+ void set(const XmlNode& node)
+ {
+ if ( magCompare(node.name(),"GeoJson"))
+ {
+ XmlNode basic = node;
+ basic.name("driver");
+ BaseDriver::set(basic);
+ basic.name("GeoJson");
+ GeoJsonDriverAttributes::set(basic);
+ }
+ }
+
+ /*!
+ \brief sets a new map
+ */
+ void set(const map<string, string>& map)
+ {
+ BaseDriver::set(map);
+ GeoJsonDriverAttributes::set(map);
+ }
+
+private:
+ MAGICS_NO_EXPORT void startPage() const;
+ MAGICS_NO_EXPORT void endPage() const;
+ MAGICS_NO_EXPORT void project(const Layout& lay) const;
+ MAGICS_NO_EXPORT void redisplay(const StaticLayer&) const;
+ MAGICS_NO_EXPORT void redisplay(const NoDataLayer&) const;
+ MAGICS_NO_EXPORT void redisplay(const StepLayer&) const;
+ MAGICS_NO_EXPORT void redisplay(const SceneLayer&) const;
+ MAGICS_NO_EXPORT void newLayer() const;
+ MAGICS_NO_EXPORT void closeLayer() const;
+
+ MAGICS_NO_EXPORT void setNewLineWidth(const MFloat) const;
+ MAGICS_NO_EXPORT void setNewColour(const Colour &col) const;
+ MAGICS_NO_EXPORT void writeColour(const Colour &col) const;
+ MAGICS_NO_EXPORT int setLineParameters(const LineStyle style, const MFloat w) const;
+
+ MAGICS_NO_EXPORT void renderPolyline(const int, MFloat *, MFloat *) const;
+ MAGICS_NO_EXPORT void renderPolyline2(const int n, MFloat *x, MFloat *y) const {}
+ MAGICS_NO_EXPORT void renderSimplePolygon(const int, MFloat *, MFloat *) const;
+ MAGICS_NO_EXPORT void renderSimplePolygon(const Polyline& line) const;
+ MAGICS_NO_EXPORT void renderText(const Text& text) const;
+ MAGICS_NO_EXPORT void circle(const MFloat x, const MFloat y, const MFloat r, const int) const {}
+ MAGICS_NO_EXPORT bool renderPixmap(MFloat,MFloat,MFloat,MFloat,int,int,unsigned char*,int, bool) const;
+ MAGICS_NO_EXPORT bool renderCellArray(const Image& obj) const;
+ MAGICS_NO_EXPORT void renderSymbols(const Symbol& symbol) const;
+ MAGICS_NO_EXPORT void renderWindArrow(const Arrow &arrow) const;
+ MAGICS_NO_EXPORT void renderWindFlag(const Flag &flag) const;
+
+ //! Method to print string about this class on to a stream of type ostream (virtual).
+ MAGICS_NO_EXPORT void print(ostream&) const;
+ MAGICS_NO_EXPORT void debugOutput(const string &s) const;
+
+ /* K M L specific */
+ MAGICS_NO_EXPORT void redisplay(const LegendLayout& legend) const;
+ MAGICS_NO_EXPORT void closePlacemark() const;
+ mutable ofstream pFile_; //!< Output stream to file.
+ mutable Layout* layout_;
+ mutable string currentLayerPath_;
+ mutable string currentTimeBegin_;
+ mutable string currentTimeEnd_;
+ mutable string currentTimeStamp_;
+ mutable bool GeoJson_placemark_;
+ mutable bool polyline_begin_;
+ mutable bool polygon_begin_;
+ mutable bool MultiGeometrySet_;
+ mutable bool layer_;
+ mutable bool render_;
+ mutable bool ecmwf_logo_;
+
+ mutable stringarray GeoJson_output_resource_list_;
+
+ //! Copy constructor - No copy allowed
+ GeoJsonDriver(const GeoJsonDriver&);
+ //! Overloaded << operator to copy - No copy allowed
+ GeoJsonDriver& operator=(const GeoJsonDriver&);
+
+ // -- Friends
+ //! Overloaded << operator to call print().
+ friend ostream& operator<<(ostream& s,const GeoJsonDriver& p)
+ { p.print(s); return s; }
+};
+
+} // namespace magics
+#endif
diff --git a/src/drivers/KMLDriver.cc b/src/drivers/KMLDriver.cc
index 24dae1d..55522b4 100755
--- a/src/drivers/KMLDriver.cc
+++ b/src/drivers/KMLDriver.cc
@@ -52,7 +52,7 @@ extern "C"{
#include <gd.h>
#endif
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
#include <cairo.h>
#include <CairoDriver.h>
#endif
@@ -338,7 +338,7 @@ MAGICS_NO_EXPORT void KMLDriver::project(const magics::Layout& layout) const
MAGICS_NO_EXPORT void KMLDriver::redisplay(const magics::LegendLayout& layout) const
{
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
//redisplay((const Layout&) legend);
const string filename = "legend.png";
cairo_surface_t* surface_ = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, layout.width(), layout.height());
@@ -796,7 +796,7 @@ MAGICS_NO_EXPORT bool KMLDriver::renderPixmap(MFloat x0,MFloat y0,MFloat x1,MFlo
if(render_)
{
if (kml_placemark_) closePlacemark();
-#ifndef MAGICS_CAIRO
+#ifndef HAVE_CAIRO
#ifndef MAGICS_RASTER
MagLog::warning() << "Image import is not implemented for the used driver!!!" << endl; return false;
#else
@@ -962,7 +962,7 @@ MAGICS_NO_EXPORT bool KMLDriver::renderCellArray(const Image& image) const
if(render_)
{
if (kml_placemark_) closePlacemark();
-#ifndef MAGICS_CAIRO
+#ifndef HAVE_CAIRO
#ifndef MAGICS_RASTER
MagLog::warning() << "Image import is not implemented for the used driver!!!" << endl; return false;
#else
diff --git a/src/drivers/MgQ/MgQLayoutItem.cc b/src/drivers/MgQ/MgQLayoutItem.cc
index ac31645..27145db 100644
--- a/src/drivers/MgQ/MgQLayoutItem.cc
+++ b/src/drivers/MgQ/MgQLayoutItem.cc
@@ -26,6 +26,7 @@
Started: February 2010
*/
+#include <QPainter>
#include <QDebug>
#include "MgQLayoutItem.h"
@@ -35,7 +36,9 @@
using namespace magics;
-MgQLayoutItem::MgQLayoutItem(const Layout &l) : layout_(l)
+MgQLayoutItem::MgQLayoutItem(const Layout &l) :
+ layout_(l),
+ clipped_(l.clipp())
{
}
@@ -46,9 +49,15 @@ MgQLayoutItem::MgQLayoutItem(const MgQLayoutItem& ori) :
dimensionX_(ori.dimensionX_),
dimensionY_(ori.dimensionY_),
projectedMinX_(ori.projectedMinX_),
- projectedMinY_(ori.projectedMinY_)
- {}
+ projectedMinY_(ori.projectedMinY_),
+ clipped_(ori.clipped_)
+{}
+
+void MgQLayoutItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+}
+
QRectF MgQLayoutItem::boundingRect() const
{
return QRectF(projectedMinX_,projectedMinY_,
diff --git a/src/drivers/MgQ/MgQLayoutItem.h b/src/drivers/MgQ/MgQLayoutItem.h
index 6c41a22..aff461c 100644
--- a/src/drivers/MgQ/MgQLayoutItem.h
+++ b/src/drivers/MgQ/MgQLayoutItem.h
@@ -50,12 +50,14 @@ public:
virtual int type() const {return Type;}
virtual QRectF boundingRect() const;
void paint(QPainter *, const QStyleOptionGraphicsItem *,
- QWidget *) {};
+ QWidget *);
const Layout& layout() {return layout_;};
AnimationRules* animationRules() {return layout_.animationRules();};
//void animationRules(AnimationRules *anr) {animationRules_=anr;};
+ bool clipped() const {return clipped_;}
+
void coordRatioX(double f) {coordRatioX_=f;};
void coordRatioY(double f) {coordRatioY_=f;};
double coordRatioX() {return coordRatioX_;};
@@ -107,6 +109,7 @@ protected:
double projectedMaxY_;
QGraphicsItem *parentItemInMainScene_;
+ bool clipped_;
//AnimationRules *animationRules_;
};
diff --git a/src/drivers/MgQ/MgQPolylineSetItem.cc b/src/drivers/MgQ/MgQPolylineSetItem.cc
index 158d87a..5682a28 100644
--- a/src/drivers/MgQ/MgQPolylineSetItem.cc
+++ b/src/drivers/MgQ/MgQPolylineSetItem.cc
@@ -77,7 +77,7 @@ void MgQPolylineSetItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
int brushIndex,penIndex;
int prevBrushIndex=-1,prevPenIndex=-1;
- //qDebug() << "POLYLINESET" << polylines_.count() << painter->clipRegion() << painter->transform().mapRect(boundingRect_);
+ //qDebug() << "POLYLINESET" << polylines_.count() << painter->clipRegion().boundingRect() << boundingRect_ << painter->transform().mapRect(boundingRect_);
bool antialias=painter->renderHints() & QPainter::Antialiasing;
diff --git a/src/drivers/MgQ/MgQScene.cc b/src/drivers/MgQ/MgQScene.cc
index 379b7b5..5d741f4 100644
--- a/src/drivers/MgQ/MgQScene.cc
+++ b/src/drivers/MgQ/MgQScene.cc
@@ -28,6 +28,8 @@
#include "MgQScene.h"
+#include "MgQ.h"
+#include "MgQLayoutItem.h"
#include <QDebug>
#include <QGraphicsItem>
@@ -134,19 +136,42 @@ void MgQScene::renderContents(QPainter *painter,
void MgQScene::renderItemRecursively(QGraphicsItem* item,QPainter *painter,const QStyleOptionGraphicsItem *option)
{
- //
if(checkItemIsVisible(item) == true &&
item->type() != MgQ::PreviewLayoutItemType)
{
painter->save();
painter->setTransform(item->sceneTransform(), true);
item->paint(painter, option, 0);
- painter->restore();
-
+ painter->restore();
+
+ bool clipSet=false;
+ QRectF oriClipRect;
+
+ if(item->type() == MgQ::LayoutItemType)
+ {
+ if(MgQLayoutItem* layout=static_cast<MgQLayoutItem*>(item))
+ {
+ if(layout->clipped())
+ {
+ painter->save();
+ clipSet=true;
+ oriClipRect=painter->clipRegion().boundingRect();
+ painter->setClipRect(item->mapToScene(item->boundingRect()).boundingRect(),
+ Qt::IntersectClip);
+ }
+ }
+ }
+
foreach(QGraphicsItem *childItem,item->childItems())
{
renderItemRecursively(childItem,painter,option);
}
+
+ if(clipSet)
+ {
+ painter->setClipRect(oriClipRect);
+ painter->restore();
+ }
}
}
@@ -159,7 +184,7 @@ bool MgQScene::checkItemIsVisible(QGraphicsItem *item)
}
else
{
- return item->data(MgQ::ItemIsVisibleKey).toBool();
+ return item->data(MgQ::ItemIsVisibleKey).toBool();
}
}
diff --git a/src/drivers/MgQ/MgQSceneItem.cc b/src/drivers/MgQ/MgQSceneItem.cc
index 6963ad4..3fb4fb3 100644
--- a/src/drivers/MgQ/MgQSceneItem.cc
+++ b/src/drivers/MgQ/MgQSceneItem.cc
@@ -376,7 +376,7 @@ void MgQSceneItem::addLayerItem(MgQLayerItem* item)
{
layerItems_.push_back(item);
//item->setStackLevel(layerItems_.count()-1);
- assert(item->layer().zindex() >= 0);
+ ASSERT(item->layer().zindex() >= 0);
item->setStackLevel(item->layer().zindex());
}
diff --git a/src/drivers/PostScriptDriver.cc b/src/drivers/PostScriptDriver.cc
index 65f0aeb..805adab 100644
--- a/src/drivers/PostScriptDriver.cc
+++ b/src/drivers/PostScriptDriver.cc
@@ -162,7 +162,7 @@ PostScriptDriver::~PostScriptDriver()
void PostScriptDriver::open()
{
currentPage_ = 0;
- setCMscale(resolution_/2.54);// cm -> pixel
+ setCMscale(300./2.54);// cm -> pixel / based on 300 DPI
if(!isSplit()) openFile();
}
@@ -190,7 +190,7 @@ MAGICS_NO_EXPORT void PostScriptDriver::startPage() const
dimensionX_ = convertCM(getXDeviceLength()); // 72 = points / inch
dimensionY_ = convertCM(getYDeviceLength()); // 2.54 = cm / inch
- MFloat resolution=resolution_;
+ MFloat resolution=300.; // work with 300 DPI
MFloat ratio=1.;
int width=0;
string mbg_tmpl = mgb_template_;
@@ -286,6 +286,10 @@ MAGICS_NO_EXPORT void PostScriptDriver::project(const magics::Layout& layout) co
fstream *ps = getStream();
*ps << "gs";
+ if(layout.clipp())
+ {
+ *ps<<" "<< offsetX_ <<" "<< offsetY_ <<" "<< dimensionX_ <<" "<< dimensionY_ <<" rectclip";
+ }
// if(fabs(X_) > 0.0001 && fabs(Y_) > 0.0001 )
*ps<<" "<< X_ <<" "<< Y_ <<" t";
*ps <<"\n";
diff --git a/src/drivers/QtDriver.cc b/src/drivers/QtDriver.cc
index f08d88d..3b5a1d5 100644
--- a/src/drivers/QtDriver.cc
+++ b/src/drivers/QtDriver.cc
@@ -42,7 +42,11 @@
#include <QDesktopWidget>
#include <QGraphicsItem>
#include <QPainter>
-#ifdef Q_WS_X11
+
+#ifdef MAGICS_QT5
+#include <QGuiApplication>
+#include <QScreen>
+#elif defined(Q_WS_X11)
#include <QX11Info>
#endif
@@ -131,22 +135,36 @@ void QtDriver::open()
currentPolylineSetItem_=0;
- //We find out the screen dpy from Qt. It can be diffrenet to the value
- //given by 'xdpyinfo' returned by scene->dpiResolution(). So we compute
- //their ratio to correctly set font size for rendering!
-#ifdef Q_WS_X11 // Do we work with a X11 display?
+ //We find out the screen dpy from Qt. It can be different to the value
+ //returned by scene->dpiResolution(), which is defined externally by
+ // a reliable command (e.g. by 'xdpyinfo') and avialiable through
+ //the env var METVIEW_SCREEN_RESOLUTION on the metview side.
+
+ //So we need to compute their ratio to correctly set font size for rendering!
+#ifdef MAGICS_QT5
+ QList<QScreen*> scList=QGuiApplication::screens();
+ const int qtDpiResolution=(!scList.isEmpty())?scList.at(0)->logicalDotsPerInchY():72;
+#elif defined(Q_WS_X11) // Do we work with a X11 display?
const int qtDpiResolution=QX11Info::appDpiY(0);
-#else // for MacOS X
- const int qtDpiResolution=72;
-#endif
- if(qtDpiResolution < 50 || qtDpiResolution > 150)
+#else // for MacOS X with Qt4
+ const int qtDpiResolution=95;
+#endif
+
+ //By default the ratio between the physical pixel size according to the external definition and Qt is 1
+ dpiResolutionRatio_=1.;
+
+ //If we have the physical pixel size from an external definition
+ if(scene->dpiResolution() != -1)
{
- dpiResolutionRatio_=1.;
+ //We compute the correct ratio
+ dpiResolutionRatio_=static_cast<float>(qtDpiResolution)/static_cast<float>(scene->dpiResolution());
}
+ //Otherwise we suppose it is the same as given by Qt (thus their ratio will be 1)
else
- {
- dpiResolutionRatio_=static_cast<float>(qtDpiResolution)/static_cast<float>(scene->dpiResolution());
- }
+ {
+ scene->setDpiResolution(qtDpiResolution);
+ }
+
setCMscale(static_cast<float>(scene->dpiResolution())/2.54); // cm -> pixel
@@ -464,7 +482,7 @@ MAGICS_NO_EXPORT void QtDriver::project(MgQLayoutItem *item) const
r->setParentItem(layoutItem);
}
#endif
-
+
//Update item history
currentItem_=item;
layoutItemStack_.push(item);
@@ -1241,11 +1259,16 @@ MAGICS_NO_EXPORT void QtDriver::renderText(const Text& text) const
if(an !=0 && an != 360)
{
+#ifdef MAGICS_QT5
+ item->setTransform(QTransform::fromTranslate(x, y), true);
+ item->setTransform(QTransform().rotate(an), true);
+ item->setTransform(QTransform::fromTranslate(-x, -y), true);
+#else
item->translate(x,y);
item->rotate(an);
- item->translate(-x,-y);
+ item->translate(-x,-y);
+#endif
}
-
item->setPos(x0,y0);
}
@@ -1329,7 +1352,7 @@ MAGICS_NO_EXPORT void QtDriver::renderText(const Text& text) const
item->setPos(x0,y0);
if(an !=0 && an != 360)
- item->rotate(an);
+ item->setRotation(an);
QTransform tr;
tr.scale(1.,-1.);
@@ -1391,6 +1414,83 @@ MAGICS_NO_EXPORT void QtDriver::renderText(const Text& text) const
MAGICS_NO_EXPORT void QtDriver::circle(const MFloat x, const MFloat y, const MFloat r, const int s) const
{
+ int fill = s;
+
+ MFloat cx=projectX(x);
+ MFloat cy=projectY(y);
+
+ //Fill wedges
+ if(fill > 0 && fill < 8)
+ {
+ QPainterPath path;
+ path.moveTo(QPointF(cx,cy));
+ path.arcTo(cx-r,cy-r,2.*r,2.*r, 45.*(fill-2.), -45.*fill);
+
+ QBrush brush(getQtColour(currentColour_));
+ QPen pen(Qt::NoPen);
+
+ QGraphicsPathItem* item=new QGraphicsPathItem(path);
+
+ item->setParentItem(currentItem_);
+ item->setPen(pen);
+ item->setBrush(brush);
+ }
+
+ //Full filled circle
+ else if(fill==8)
+ {
+ QPainterPath path;
+
+ path.addEllipse(QPointF(cx,cy),r,r);
+
+ QBrush brush(getQtColour(currentColour_));
+ QPen pen(Qt::NoPen);
+
+ QGraphicsPathItem* item=new QGraphicsPathItem(path);
+
+ item->setParentItem(currentItem_);
+ item->setPen(pen);
+ item->setBrush(brush);
+ }
+
+ //Full filled circle whit a white vertical bar in the middle
+ else if(fill == 9)
+ {
+ QPainterPath path;
+
+ path.arcMoveTo(cx-r,cy-r,2.*r,2.*r,110);
+ path.arcTo(cx-r,cy-r,2.*r,2.*r, 110, 140);
+ path.closeSubpath();
+
+ path.arcMoveTo(cx-r,cy-r,2.*r,2.*r,290);
+ path.arcTo(cx-r,cy-r,2.*r,2.*r, 290, 140);
+ path.closeSubpath();
+
+ QBrush brush(getQtColour(currentColour_));
+ QPen pen(Qt::NoPen);
+
+ QGraphicsPathItem* item=new QGraphicsPathItem(path);
+
+ item->setParentItem(currentItem_);
+ item->setPen(pen);
+ item->setBrush(brush);
+ }
+
+ //Outline
+ if(fill < 8)
+ {
+ QPainterPath path;
+ path.addEllipse(QPointF(cx,cy),r,r);
+
+ QBrush brush(Qt::NoBrush);
+ QPen pen(getQtColour(currentColour_));
+
+ QGraphicsPathItem* item=new QGraphicsPathItem(path);
+
+ item->setParentItem(currentItem_);
+ item->setPen(pen);
+ item->setBrush(brush);
+ }
}
MAGICS_NO_EXPORT void QtDriver::circle(const MFloat x, const MFloat y, const MFloat r, const int s,MgQSymbolItem *qSym) const
diff --git a/src/drivers/SVGDriver.cc b/src/drivers/SVGDriver.cc
index 3f478ef..d8c5215 100644
--- a/src/drivers/SVGDriver.cc
+++ b/src/drivers/SVGDriver.cc
@@ -329,6 +329,7 @@ MAGICS_NO_EXPORT void SVGDriver::project(const magics::Layout& layout) const
dimensionStack_.push(dimensionX_);
dimensionStack_.push(dimensionY_);
const MFloat oldHeight = dimensionY_;
+ const MFloat oldWidth = dimensionX_;
scalesX_.push(coordRatioX_);
scalesY_.push(coordRatioY_);
@@ -351,12 +352,26 @@ MAGICS_NO_EXPORT void SVGDriver::project(const magics::Layout& layout) const
group_counter_++;
+ if(layout.clipp())
+ {
+ const double clip_height=projectY(layout.maxY())-projectY(layout.minY());
+ pFile_ << "<defs>\n"
+ << " <clipPath id=\"clip_"<<layout.name()<<"\">\n"
+// << " <rect x=\""<<projectX(layout.minX())<<"\" y=\""<<projectY(layout.minY())-setY(y_set)<<"\" width=\""<<projectX(layout.maxX())-projectX(layout.minX())<<"\" height=\""<<projectY(layout.maxY())-projectY(layout.minY())<<"\" />\n"
+ << " <rect x=\""<<projectX(layout.minX())<<"\" y=\""<<projectY(setY(layout.minY()))-clip_height<<"\" width=\""<<projectX(layout.maxX())-projectX(layout.minX())<<"\" height=\""<<clip_height<<"\" />\n"
+ << " </clipPath>\n"
+ << "</defs>"<<endl;
+ }
+
pFile_ << "<g";
if(!layout.name().empty()) pFile_ << " id=\""<<layout.name()<<"\"";
if( !zero(x_set) || !zero(y_set) ) pFile_ << " transform=\"translate("<<x_set <<","<<setY(y_set)<<")\"";
- //if(showCoordinates_ && area=="drawing_area") pFile_ << " onmouseover=\"setLonScale("<<coordRatioX_<<");showCoords(evt)\"";
- //if(box->getClip()) pFile_ << " clip-path=\"url(#clip_"<<area<<")\"";
+ //if(showCoordinates_ && area=="drawing_area") pFile_ << " onmouseover=\"setLonScale("<<coordRatioX_<<");showCoords(evt)\"";
+ if(layout.clipp())
+ {
+ pFile_ << " clip-path=\"url(#clip_"<<layout.name()<<")\"";
+ }
pFile_ << ">\n";
if(layout.isNavigable())
@@ -647,7 +662,7 @@ MAGICS_NO_EXPORT void SVGDriver::renderPolyline(const int n, MFloat *x, MFloat *
MAGICS_NO_EXPORT void SVGDriver::renderPolyline2(const int n, MFloat* x, MFloat* y) const
{
if(n != 2 || (currentColour_==Colour("none")) ) return;
- closeGroup();
+// closeGroup();
const int r = static_cast<int>(currentColour_.red() *255);
const int g = static_cast<int>(currentColour_.green()*255);
const int b = static_cast<int>(currentColour_.blue() *255);
@@ -993,20 +1008,13 @@ MAGICS_NO_EXPORT void SVGDriver::renderText(const Text& text) const
setNewColour(magfont.colour());
const MFloat dheight = magfont.size()*text_scale;
const std::set<string>& styles = magfont.styles();
-// for (std::set<string>::iterator it=styles.begin(); it!=styles.end(); ++it)
-// std::cout << '_' << *it;
-// string style = "";
-// if(styles.find("bolditalic") != styles.end()) style = "bolditalic";
-// else if(styles.find("bold") != styles.end()) style = "bold";
-// else if(styles.find("italic") != styles.end()) style = "italic";
string style = "normal";
-// cout << "___"<<style<<endl;
const string font = magfont.name()+"_"+style;
- if (verticalAlign==MBASE ) vertical = dheight * .15;
- else if (verticalAlign==MTOP) vertical = dheight;
- else if (verticalAlign==MHALF) vertical = dheight * .5;
-// default else if (verticalAlign==MBOTTOM) vertical = 0.;
-// vertical = -vertical/dheight *100;
+
+ string verticalJustification = "no-change";
+ if (verticalAlign==MBASE ) verticalJustification = "alphabetic";
+ else if (verticalAlign==MTOP) verticalJustification = "hanging";
+ else if (verticalAlign==MHALF) verticalJustification = "middle";
fontMapIter iter = FontMap_.find(font);
string ttf;
@@ -1037,13 +1045,10 @@ MAGICS_NO_EXPORT void SVGDriver::renderText(const Text& text) const
openGroup(stream.str());
}
- pFile_ << "<text x=\""<<xxx<<"\" y=\""<<yyy<<"\"";
+ pFile_ << "<text x=\""<<xxx<<"\" y=\""<<yyy<<"\" dominant-baseline=\""<<verticalJustification<< "\"";
// if(text.getBlanking())
// pFile_ << " background-color=\"white\"";
- if(zero(vertical))
- pFile_ << ">"<<(*niceText).text();
- else
- pFile_ << "><tspan dy=\""<<vertical<<"cm\">"<<(*niceText).text()<<"</tspan>";
+ pFile_ << ">"<<(*niceText).text();
}
else
{
@@ -1059,7 +1064,6 @@ MAGICS_NO_EXPORT void SVGDriver::renderText(const Text& text) const
}// end for all strings
pFile_ <<"</text>\n";
}// end for all co-ordinates
-// pFile_ <<"</g>\n";
}
/*!
@@ -1483,8 +1487,7 @@ MAGICS_NO_EXPORT void SVGDriver::renderSymbols(const Symbol& symbol) const
const MFloat y = projectY(symbol[0].y());
string logofile;
- if(magCompare(location,"WWW")) logofile = "http://old.ecmwf.int/publications/manuals/magics/magplus/resources/ecmwf_logo.png";
- else if(magCompare(location,"LOCAL")) logofile = "ecmwf_logo.png";
+ if(magCompare(location,"LOCAL")) logofile = "ecmwf_logo.png";
else logofile = getEnvVariable("MAGPLUS_HOME") + MAGPLUS_PATH_TO_SHARE_ + "ecmwf_logo.png";
svg_output_resource_list_.push_back(logofile);
pFile_ << "<a xlink:href=\"http://www.ecmwf.int\">"
diff --git a/src/drivers/libimagequant/COPYRIGHT b/src/drivers/libimagequant/COPYRIGHT
new file mode 100644
index 0000000..98de36b
--- /dev/null
+++ b/src/drivers/libimagequant/COPYRIGHT
@@ -0,0 +1,36 @@
+© 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
+© 2009-2014 by Kornel Lesiński.
+
+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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+© 1989, 1991 by Jef Poskanzer.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation. This software is provided "as is" without express or
+implied warranty.
diff --git a/src/drivers/libimagequant/MANUAL.md b/src/drivers/libimagequant/MANUAL.md
new file mode 100644
index 0000000..5eed37a
--- /dev/null
+++ b/src/drivers/libimagequant/MANUAL.md
@@ -0,0 +1,478 @@
+# libimagequant—Image Quantization Library
+
+Small, portable C library for high-quality conversion of RGBA images to 8-bit indexed-color (palette) images.
+It's powering [pngquant2](http://pngquant.org).
+
+## License
+
+[BSD](https://raw.github.com/pornel/pngquant/master/lib/COPYRIGHT).
+It can be linked with both free and closed-source software.
+
+## Download
+
+The [library](http://pngquant.org/lib) is currently a part of the [pngquant2 project](https://github.com/pornel/pngquant/tree/master/lib).
+
+Files needed for the library are only in the `lib/` directory inside the repository (and you can ignore the rest).
+
+## Compiling and Linking
+
+The library can be linked with ANSI C and C++ programs. It has no external dependencies.
+
+To build on Unix-like systems run:
+
+ make -C lib
+
+it will create `lib/libimagequant.a` which you can link with your program.
+
+ gcc yourprogram.c /path/to/lib/libimagequant.a
+
+On BSD, use `gmake` (GNU make) rather than the native `make`.
+
+Alternatively you can compile the library with your program simply by including all `.c` files (and define `NDEBUG` to get a fast version):
+
+ gcc -std=c99 -O3 -DNDEBUG lib/*.c yourprogram.c
+
+### Compiling on Windows/Visual Studio
+
+The library can be compiled with any C compiler that has at least basic support for C99 (GCC, clang, ICC, C++ Builder, even Tiny C Compiler), but Visual Studio 2012 and older are not up to date with the 1999 C standard. There are 2 options for using `libimagequant` on Windows:
+
+ * Use Visual Studio **2013** (MSVC 18) and an [MSVC-compatible branch of the library](https://github.com/pornel/pngquant/tree/msvc/lib)
+ * Or use GCC from [MinGW](http://www.mingw.org). Use GCC to build `libimagequant.a` (using the instructions above for Unix) and add it along with `libgcc.a` (shipped with the MinGW compiler) to your VC project.
+
+## Overview
+
+The basic flow is:
+
+1. Create attributes object and configure the library.
+2. Create image object from RGBA bitmap or data source.
+3. Perform quantization (generate palette).
+4. Store remapped image and final palette.
+5. Free memory.
+
+Please note that libimagequant only handles raw uncompressed bitmaps in memory and is completely independent of any file format.
+
+<p>
+
+ #include "lib/libimagequant.h"
+
+ liq_attr *attr = liq_attr_create();
+ liq_image *image = liq_image_create_rgba(attr, bitmap, width, height, 0);
+ liq_result *res = liq_quantize_image(attr, image);
+
+ liq_write_remapped_image(res, image, bitmap, bitmap_size);
+ const liq_palette *pal = liq_get_palette(res);
+
+ // use image and palette here
+
+ liq_attr_destroy(attr);
+ liq_image_destroy(image);
+ liq_result_destroy(res);
+
+Functions returning `liq_error` return `LIQ_OK` (`0`) on success and non-zero on error.
+
+It's safe to pass `NULL` to any function accepting `liq_attr`, `liq_image`, `liq_result` (in that case the error code `LIQ_INVALID_POINTER` will be returned). These objects can be reused multiple times.
+
+There are 3 ways to create image object for quantization:
+
+ * `liq_image_create_rgba()` for simple, contiguous RGBA bitmaps (width×height×4 bytes large array).
+ * `liq_image_create_rgba_rows()` for non-contiguous RGBA bitmaps (that have padding between rows or reverse order, e.g. BMP).
+ * `liq_image_create_custom()` for RGB, ABGR, YUV and all other formats that can be converted on-the-fly to RGBA (you have to supply the conversion function).
+
+Note that "image" here means raw uncompressed pixels. If you have a compressed image file, such as PNG, you must use another library (e.g. libpng or lodepng) to decode it first.
+
+## Functions
+
+----
+
+ liq_attr* liq_attr_create(void);
+
+Returns object that will hold initial settings (attributes) for the library. The object should be freed using `liq_attr_destroy()` after it's no longer needed.
+
+Returns `NULL` in the unlikely case that the library cannot run on the current machine (e.g. the library has been compiled for SSE-capable x86 CPU and run on VIA C3 CPU).
+
+----
+
+ liq_error liq_set_max_colors(liq_attr* attr, int colors);
+
+Specifies maximum number of colors to use. The default is 256. Instead of setting a fixed limit it's better to use `liq_set_quality()`.
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if number of colors is outside the range 2-256.
+
+----
+
+ int liq_get_max_colors(liq_attr* attr);
+
+Returns the value set by `liq_set_max_colors()`.
+
+----
+
+ liq_error liq_set_quality(liq_attr* attr, int minimum, int maximum);
+
+Quality is in range `0` (worst) to `100` (best) and values are analoguous to JPEG quality (i.e. `80` is usually good enough).
+
+Quantization will attempt to use the lowest number of colors needed to achieve `maximum` quality. `maximum` value of `100` is the default and means conversion as good as possible.
+
+If it's not possible to convert the image with at least `minimum` quality (i.e. 256 colors is not enough to meet the minimum quality), then `liq_quantize_image()` will fail. The default minumum is `0` (proceeds regardless of quality).
+
+Quality measures how well the generated palette fits image given to `liq_quantize_image()`. If a different image is remapped with `liq_write_remapped_image()` then actual quality may be different.
+
+Regardless of the quality settings the number of colors won't exceed the maximum (see `liq_set_max_colors()`).
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if target is lower than minimum or any of them is outside the 0-100 range.
+Returns `LIQ_INVALID_POINTER` if `attr` appears to be invalid.
+
+ liq_attr *attr = liq_attr_create();
+ liq_set_quality(attr, 50, 80); // use quality 80 if possible. Give up if quality drops below 50.
+
+----
+
+ int liq_get_min_quality(liq_attr* attr);
+
+Returns the lower bound set by `liq_set_quality()`.
+
+----
+
+ int liq_get_max_quality(liq_attr* attr);
+
+Returns the upper bound set by `liq_set_quality()`.
+
+----
+
+ liq_image *liq_image_create_rgba(liq_attr *attr, void* bitmap, int width, int height, double gamma);
+
+Creates image object that represents a bitmap later used for quantization and remapping. The bitmap must be contiguous run of RGBA pixels (alpha is the last component, 0 = transparent, 255 = opaque).
+
+The bitmap must not be modified or freed until this object is freed with `liq_image_destroy()`. See also `liq_image_set_memory_ownership()`.
+
+`width` and `height` are dimensions in pixels. An image 10x10 pixel large will need 400-byte bitmap.
+
+`gamma` can be `0` for images with the typical 1/2.2 [gamma](http://en.wikipedia.org/wiki/Gamma_correction).
+Otherwise `gamma` must be > 0 and < 1, e.g. `0.45455` (1/2.2) or `0.55555` (1/1.8). Generated palette will use the same gamma unless `liq_set_output_gamma()` is used. If `liq_set_output_gamma` is not used, then it only affects whether brighter or darker areas of the image will get more palette colors allocated.
+
+Returns `NULL` on failure, e.g. if `bitmap` is `NULL` or `width`/`height` is <= 0.
+
+----
+
+ liq_image *liq_image_create_rgba_rows(liq_attr *attr, void* rows[], int width, int height, double gamma);
+
+Same as `liq_image_create_rgba()`, but takes array of pointers to rows in the bitmap. This allows defining bitmaps with reversed rows (like in BMP), "stride" different than width or using only fragment of a larger bitmap, etc.
+
+`rows` array must have at least `height` elements and each row must be at least `width` RGBA pixels wide.
+
+ unsigned char *bitmap = …;
+ void *rows = malloc(height * sizeof(void*));
+ int bytes_per_row = width * 4 + padding; // stride
+ for(int i=0; i < height; i++) {
+ rows[i] = bitmap + i * bytes_per_row;
+ }
+ liq_image *img = liq_image_create_rgba_rows(attr, rows, width, height, 0);
+ // …
+ liq_image_destroy(img);
+ free(rows);
+
+The row pointers and bitmap must not be modified or freed until this object is freed with `liq_image_destroy()` (you can change that with `liq_image_set_memory_ownership()`).
+
+See also `liq_image_create_rgba()` and `liq_image_create_custom()`.
+
+----
+
+ liq_result *liq_quantize_image(liq_attr *attr, liq_image *input_image);
+
+Performs quantization (palette generation) based on settings in `attr` and pixels of the image.
+
+Returns `NULL` if quantization fails, e.g. due to limit set in `liq_set_quality()`.
+
+See `liq_write_remapped_image()`.
+
+----
+
+ liq_error liq_set_dithering_level(liq_result *res, float dither_level);
+
+Enables/disables dithering in `liq_write_remapped_image()`. Dithering level must be between `0` and `1` (inclusive). Dithering level `0` enables fast non-dithered remapping. Otherwise a variation of Floyd-Steinberg error diffusion is used.
+
+Precision of the dithering algorithm depends on the speed setting, see `liq_set_speed()`.
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if the dithering level is outside the 0-1 range.
+
+----
+
+ liq_error liq_write_remapped_image(liq_result *result, liq_image *input_image, void *buffer, size_t buffer_size);
+
+Remaps the image to palette and writes its pixels to the given buffer, 1 pixel per byte. Buffer must be large enough to fit the entire image, i.e. width×height bytes large. For safety, pass size of the buffer as `buffer_size`.
+
+For best performance call `liq_get_palette()` *after* this function, as palette is improved during remapping.
+
+Returns `LIQ_BUFFER_TOO_SMALL` if given size of the buffer is not enough to fit the entire image.
+
+ int buffer_size = width*height;
+ char *buffer = malloc(buffer_size);
+ if (LIQ_OK == liq_write_remapped_image(result, input_image, buffer, buffer_size)) {
+ liq_palette *pal = liq_get_palette(result);
+ // save image
+ }
+
+See `liq_get_palette()` and `liq_write_remapped_image_rows()`.
+
+Please note that it only writes raw uncompressed pixels to memory. It does not perform any compression. If you'd like to create a PNG file then you need to pass the raw pixel data to another library, e.g. libpng or lodepng. See `rwpng.c` in `pngquant` project for an example how to do that.
+
+----
+
+ const liq_palette *liq_get_palette(liq_result *result);
+
+Returns pointer to palette optimized for image that has been quantized or remapped (final refinements are applied to the palette during remapping).
+
+It's valid to call this method before remapping, if you don't plan to remap any images or want to use same palette for multiple images.
+
+`liq_palette->count` contains number of colors (up to 256), `liq_palette->entries[n]` contains RGBA value for nth palette color.
+
+The palette is **temporary and read-only**. You must copy the palette elsewhere *before* calling `liq_result_destroy()`.
+
+Returns `NULL` on error.
+
+----
+
+ void liq_attr_destroy(liq_attr *);
+ void liq_image_destroy(liq_image *);
+ void liq_result_destroy(liq_result *);
+
+Releases memory owned by the given object. Object must not be used any more after it has been freed.
+
+Freeing `liq_result` also frees any `liq_palette` obtained from it.
+
+## Advanced Functions
+
+----
+
+ liq_error liq_set_speed(liq_attr* attr, int speed);
+
+Higher speed levels disable expensive algorithms and reduce quantization precision. The default speed is `3`. Speed `1` gives marginally better quality at significant CPU cost. Speed `10` has usually 5% lower quality, but is 8 times faster than the default.
+
+High speeds combined with `liq_set_quality()` will use more colors than necessary and will be less likely to meet minimum required quality.
+
+<table><caption>Features dependent on speed</caption>
+<tr><th>Noise-sensitive dithering</th><td>speed 1 to 5</td></tr>
+<tr><th>Forced posterization</th><td>8-10 or if image has more than million colors</td></tr>
+<tr><th>Quantization error known</th><td>1-7 or if minimum quality is set</td></tr>
+<tr><th>Additional quantization techniques</th><td>1-6</td></tr>
+</table>
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if the speed is outside the 1-10 range.
+
+----
+
+ int liq_get_speed(liq_attr* attr);
+
+Returns the value set by `liq_set_speed()`.
+
+----
+
+ liq_error liq_set_min_opacity(liq_attr* attr, int min);
+
+Alpha values higher than this will be rounded to opaque. This is a workaround for Internet Explorer 6 that truncates semitransparent values to completely transparent. The default is `255` (no change). 238 is a suggested value.
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if the value is outside the 0-255 range.
+
+----
+
+ int liq_get_min_opacity(liq_attr* attr);
+
+Returns the value set by `liq_set_min_opacity()`.
+
+----
+
+ liq_set_min_posterization(liq_attr* attr, int bits);
+
+Ignores given number of least significant bits in all channels, posterizing image to `2^bits` levels. `0` gives full quality. Use `2` for VGA or 16-bit RGB565 displays, `4` if image is going to be output on a RGB444/RGBA4444 display (e.g. low-quality textures on Android).
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if the value is outside the 0-4 range.
+
+----
+
+ int liq_get_min_posterization(liq_attr* attr);
+
+Returns the value set by `liq_set_min_posterization()`.
+
+----
+
+ liq_set_last_index_transparent(liq_attr* attr, int is_last);
+
+`0` (default) makes alpha colors sorted before opaque colors. Non-`0` mixes colors together except completely transparent color, which is moved to the end of the palette. This is a workaround for programs that blindly assume the last palette entry is transparent.
+
+----
+
+ liq_image *liq_image_create_custom(liq_attr *attr, liq_image_get_rgba_row_callback *row_callback, void *user_info, int width, int height, double gamma);
+
+<p>
+
+ void image_get_rgba_row_callback(liq_color row_out[], int row_index, int width, void *user_info) {
+ for(int column_index=0; column_index < width; column_index++) {
+ row_out[column_index] = /* generate pixel at (row_index, column_index) */;
+ }
+ }
+
+Creates image object that will use callback to read image data. This allows on-the-fly conversion of images that are not in the RGBA color space.
+
+`user_info` value will be passed to the callback. It may be useful for storing pointer to program's internal representation of the image.
+
+The callback must read/generate `row_index`-th row and write its RGBA pixels to the `row_out` array. Row `width` is given for convenience and will always equal to image width.
+
+The callback will be called multiple times for each row. Quantization and remapping require at least two full passes over image data, so caching of callback's work makes no sense — in such case it's better to convert entire image and use `liq_image_create_rgba()` instead.
+
+To use RGB image:
+
+ void rgb_to_rgba_callback(liq_color row_out[], int row_index, int width, void *user_info) {
+ unsigned char *rgb_row = ((unsigned char *)user_info) + 3*width*row_index;
+
+ for(int i=0; i < width; i++) {
+ row_out[i].r = rgb_row[i*3];
+ row_out[i].g = rgb_row[i*3+1];
+ row_out[i].b = rgb_row[i*3+2];
+ row_out[i].a = 255;
+ }
+ }
+ liq_image *img = liq_image_create_custom(attr, rgb_to_rgba_callback, rgb_bitmap, width, height, 0);
+
+The library doesn't support RGB bitmaps "natively", because supporting only single format allows compiler to inline more code, 4-byte pixel alignment is faster, and SSE instructions operate on 4 values at once, so alpha support is almost free.
+
+----
+
+ liq_error liq_image_set_memory_ownership(liq_image *image, int ownership_flags);
+
+Passes ownership of bitmap and/or rows memory to the `liq_image` object, so you don't have to free it yourself. Memory owned by the object will be freed at its discretion with `free` function specified in `liq_attr_create_with_allocator()` (by default it's stdlib's `free()`).
+
+* `LIQ_OWN_PIXELS` makes bitmap owned by the object. The bitmap will be freed automatically at any point when it's no longer needed. If you set this flag you must **not** free the bitmap yourself. If the image has been created with `liq_image_create_rgba_rows()` then the bitmap address is assumed to be the lowest address of any row.
+
+* `LIQ_OWN_ROWS` makes array of row pointers (but not bitmap pointed by these rows) owned by the object. Rows will be freed when object is deallocated. If you set this flag you must **not** free the rows array yourself. This flag is valid only if the object has been created with `liq_image_create_rgba_rows()`.
+
+These flags can be combined with binary *or*, i.e. `LIQ_OWN_PIXELS | LIQ_OWN_ROWS`.
+
+This function must not be used if the image has been created with `liq_image_create_custom()`.
+
+Returns `LIQ_VALUE_OUT_OF_RANGE` if invalid flags are specified or image is not backed by a bitmap.
+
+----
+
+ liq_error liq_write_remapped_image_rows(liq_result *result, liq_image *input_image, unsigned char **row_pointers);
+
+Similar to `liq_write_remapped_image()`. Writes remapped image, at 1 byte per pixel, to each row pointed by `row_pointers` array. The array must have at least as many elements as height of the image, and each row must have at least as many bytes as width of the image. Rows must not overlap.
+
+For best performance call `liq_get_palette()` *after* this function, as remapping may change the palette.
+
+Returns `LIQ_INVALID_POINTER` if `result` or `input_image` is `NULL`.
+
+----
+
+ double liq_get_quantization_error(liq_result *result);
+
+Returns mean square error of quantization (square of difference between pixel values in the original image and remapped image). Alpha channel and gamma correction are taken into account, so the result isn't exactly the mean square error of all channels.
+
+For most images MSE 1-5 is excellent. 7-10 is OK. 20-30 will have noticeable errors. 100 is awful.
+
+This function should be called *after* `liq_write_remapped_image()`. It may return `-1` if the value is not available (this is affected by `liq_set_speed()` and `liq_set_quality()`).
+
+----
+
+ double liq_get_quantization_quality(liq_result *result);
+
+Analoguous to `liq_get_quantization_error()`, but returns quantization error as quality value in the same 0-100 range that is used by `liq_set_quality()`.
+
+This function should be called *after* `liq_write_remapped_image()`. It may return `-1` if the value is not available (this is affected by `liq_set_speed()` and `liq_set_quality()`).
+
+This function can be used to add upper limit to quality options presented to the user, e.g.
+
+ liq_attr *attr = liq_attr_create();
+ liq_image *img = liq_image_create_rgba(…);
+ liq_result *res = liq_quantize_image(attr, img);
+ int max_attainable_quality = liq_get_quantization_quality(res);
+ printf("Please select quality between 0 and %d: ", max_attainable_quality);
+ int user_selected_quality = prompt();
+ if (user_selected_quality < max_attainable_quality) {
+ liq_set_quality(user_selected_quality, 0);
+ liq_result_destroy(res);
+ res = liq_quantize_image(attr, img);
+ }
+ liq_write_remapped_image(…);
+
+----
+
+ void liq_set_log_callback(liq_attr*, liq_log_callback_function*, void *user_info);
+
+<p>
+
+ void log_callback_function(const liq_attr*, const char *message, void *user_info) {}
+
+----
+
+ void liq_set_log_flush_callback(liq_attr*, liq_log_flush_callback_function*, void *user_info);
+<p>
+
+ void log_flush_callback_function(const liq_attr*, void *user_info) {}
+
+Sets up callback function to be called when the library reports work progress or errors. The callback must not call any library functions.
+
+`user_info` value will be passed to the callback.
+
+`NULL` callback clears the current callback.
+
+In the log callback the `message` is a zero-terminated string containing informative message to output. It is valid only until the callback returns.
+
+`liq_set_log_flush_callback()` sets up callback function that will be called after the last log callback, which can be used to flush buffers and free resources used by the log callback.
+
+----
+
+ liq_attr* liq_attr_create_with_allocator(void* (*malloc)(size_t), void (*free)(void*));
+
+Same as `liq_attr_create`, but uses given `malloc` and `free` replacements to allocate all memory used by the library.
+
+The `malloc` function must return 16-byte aligned memory on x86 (and on other architectures memory aligned for `double` and pointers). Conversely, if your stdlib's `malloc` doesn't return appropriately aligned memory, you should use this function to provide aligned replacements.
+
+----
+
+ liq_attr* liq_attr_copy(liq_attr *orig);
+
+Creates an independent copy of `liq_attr`. The copy should also be freed using `liq_attr_destroy()`.
+
+---
+
+ liq_error liq_set_output_gamma(liq_result* res, double gamma);
+
+Sets gamma correction for generated palette and remapped image. Must be > 0 and < 1, e.g. `0.45455` for gamma 1/2.2 in PNG images. By default output gamma is same as gamma of the input image.
+
+----
+
+ int liq_image_get_width(const liq_image *img);
+ int liq_image_get_height(const liq_image *img);
+ double liq_get_output_gamma(const liq_result *result);
+
+Getters for `width`, `height` and `gamma` of the input image.
+
+If the input is invalid, these all return -1.
+
+---
+
+ int liq_version();
+
+Returns version of the library as an integer. Same as `LIQ_VERSION`. Human-readable version is defined as `LIQ_VERSION_STRING`.
+
+## Multithreading
+
+The library is stateless and doesn't use any global or thread-local storage. It doesn't use any locks.
+
+* Different threads can perform unrelated quantizations/remappings at the same time (e.g. each thread working on a different image).
+* The same `liq_attr`, `liq_result`, etc. can be accessed from different threads, but not at the same time (e.g. you can create `liq_attr` in one thread and free it in another).
+
+The library needs to sort unique colors present in the image. Although the sorting algorithm does few things to make stack usage minimal in typical cases, there is no guarantee against extremely degenerate cases, so threads should have automatically growing stack.
+
+### OpenMP
+
+The library will parallelize some operations if compiled with OpenMP.
+
+You must not increase number of maximum threads after `liq_image` has been created, as it allocates some per-thread buffers.
+
+Callback of `liq_image_create_custom()` may be called from different threads at the same time.
+
+## Acknowledgements
+
+Thanks to Irfan Skiljan for helping test the first version of the library.
+
+The library is developed by [Kornel Lesiński](mailto:%20kornel at pngquant.org).
diff --git a/src/drivers/libimagequant/Makefile b/src/drivers/libimagequant/Makefile
new file mode 100644
index 0000000..284e745
--- /dev/null
+++ b/src/drivers/libimagequant/Makefile
@@ -0,0 +1,65 @@
+-include config.mk
+
+STATICLIB=libimagequant.a
+SHAREDLIB=libimagequant.so.0
+
+DLL=libimagequant.dll
+DLLIMP=libimagequant_dll.a
+DLLDEF=libimagequant_dll.def
+
+OBJS = pam.o mediancut.o blur.o mempool.o viter.o nearest.o libimagequant.o
+SHAREDOBJS = $(subst .o,.lo,$(OBJS))
+
+BUILD_CONFIGURATION="$(CC) $(CFLAGS) $(LDFLAGS)"
+
+DISTFILES = $(OBJS:.o=.c) *.h MANUAL.md COPYRIGHT Makefile configure
+TARNAME = libimagequant-$(VERSION)
+TARFILE = $(TARNAME)-src.tar.bz2
+
+all: static shared
+
+static: $(STATICLIB)
+
+shared: $(SHAREDLIB)
+
+dll:
+ $(MAKE) CFLAGSADD="-DLIQ_EXPORT='__declspec(dllexport)'" $(DLL)
+
+
+$(DLL) $(DLLIMP): $(OBJS)
+ $(CC) -fPIC -shared -o $(DLL) $^ $(LDFLAGS) -Wl,--out-implib,$(DLLIMP),--output-def,$(DLLDEF)
+
+$(STATICLIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $^
+
+$(SHAREDOBJS):
+ $(CC) -fPIC $(CFLAGS) -c $(@:.lo=.c) -o $@
+
+$(SHAREDLIB): $(SHAREDOBJS)
+ $(CC) -shared -o $@ $^ $(LDFLAGS)
+
+$(OBJS): $(wildcard *.h) config.mk
+
+dist: $(TARFILE)
+
+$(TARFILE): $(DISTFILES)
+ rm -rf $(TARFILE) $(TARNAME)
+ mkdir $(TARNAME)
+ cp $(DISTFILES) $(TARNAME)
+ tar -cjf $(TARFILE) --numeric-owner --exclude='._*' $(TARNAME)
+ rm -rf $(TARNAME)
+ -shasum $(TARFILE)
+
+clean:
+ rm -f $(OBJS) $(SHAREDOBJS) $(SHAREDLIB) $(STATICLIB) $(TARFILE) $(DLL) $(DLLIMP) $(DLLDEF)
+
+distclean: clean
+ rm -f config.mk
+
+config.mk:
+ifeq ($(filter %clean %distclean, $(MAKECMDGOALS)), )
+ ./configure
+endif
+
+.PHONY: all static shared clean dist distclean dll
+.DELETE_ON_ERROR:
diff --git a/src/drivers/libimagequant/blur.c b/src/drivers/libimagequant/blur.c
new file mode 100644
index 0000000..9158ad4
--- /dev/null
+++ b/src/drivers/libimagequant/blur.c
@@ -0,0 +1,112 @@
+
+#include "libimagequant.h"
+#include "pam.h"
+#include "blur.h"
+
+/*
+ Blurs image horizontally (width 2*size+1) and writes it transposed to dst (called twice gives 2d blur)
+ */
+static void transposing_1d_blur(unsigned char *restrict src, unsigned char *restrict dst, unsigned int width, unsigned int height, const unsigned int size)
+{
+ for(unsigned int j=0; j < height; j++) {
+ unsigned char *restrict row = src + j*width;
+
+ // accumulate sum for pixels outside line
+ unsigned int sum;
+ sum = row[0]*size;
+ for(unsigned int i=0; i < size; i++) {
+ sum += row[i];
+ }
+
+ // blur with left side outside line
+ for(unsigned int i=0; i < size; i++) {
+ sum -= row[0];
+ sum += row[i+size];
+
+ dst[i*height + j] = sum / (size*2);
+ }
+
+ for(unsigned int i=size; i < width-size; i++) {
+ sum -= row[i-size];
+ sum += row[i+size];
+
+ dst[i*height + j] = sum / (size*2);
+ }
+
+ // blur with right side outside line
+ for(unsigned int i=width-size; i < width; i++) {
+ sum -= row[i-size];
+ sum += row[width-1];
+
+ dst[i*height + j] = sum / (size*2);
+ }
+ }
+}
+
+/**
+ * Picks maximum of neighboring pixels (blur + lighten)
+ */
+LIQ_PRIVATE void liq_max3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height)
+{
+ for(unsigned int j=0; j < height; j++) {
+ const unsigned char *row = src + j*width,
+ *prevrow = src + (j > 1 ? j-1 : 0)*width,
+ *nextrow = src + MIN(height-1,j+1)*width;
+
+ unsigned char prev,curr=row[0],next=row[0];
+
+ for(unsigned int i=0; i < width-1; i++) {
+ prev=curr;
+ curr=next;
+ next=row[i+1];
+
+ unsigned char t1 = MAX(prev,next);
+ unsigned char t2 = MAX(nextrow[i],prevrow[i]);
+ *dst++ = MAX(curr,MAX(t1,t2));
+ }
+ unsigned char t1 = MAX(curr,next);
+ unsigned char t2 = MAX(nextrow[width-1],prevrow[width-1]);
+ *dst++ = MAX(t1,t2);
+ }
+}
+
+/**
+ * Picks minimum of neighboring pixels (blur + darken)
+ */
+LIQ_PRIVATE void liq_min3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height)
+{
+ for(unsigned int j=0; j < height; j++) {
+ const unsigned char *row = src + j*width,
+ *prevrow = src + (j > 1 ? j-1 : 0)*width,
+ *nextrow = src + MIN(height-1,j+1)*width;
+
+ unsigned char prev,curr=row[0],next=row[0];
+
+ for(unsigned int i=0; i < width-1; i++) {
+ prev=curr;
+ curr=next;
+ next=row[i+1];
+
+ unsigned char t1 = MIN(prev,next);
+ unsigned char t2 = MIN(nextrow[i],prevrow[i]);
+ *dst++ = MIN(curr,MIN(t1,t2));
+ }
+ unsigned char t1 = MIN(curr,next);
+ unsigned char t2 = MIN(nextrow[width-1],prevrow[width-1]);
+ *dst++ = MIN(t1,t2);
+ }
+}
+
+/*
+ Filters src image and saves it to dst, overwriting tmp in the process.
+ Image must be width*height pixels high. Size controls radius of box blur.
+ */
+LIQ_PRIVATE void liq_blur(unsigned char *src, unsigned char *tmp, unsigned char *dst, unsigned int width, unsigned int height, unsigned int size)
+{
+ assert(size > 0);
+ if (width < 2*size+1 || height < 2*size+1) {
+ return;
+ }
+ transposing_1d_blur(src, tmp, width, height, size);
+ transposing_1d_blur(tmp, dst, height, width, size);
+}
diff --git a/src/drivers/libimagequant/blur.h b/src/drivers/libimagequant/blur.h
new file mode 100644
index 0000000..06ae8cb
--- /dev/null
+++ b/src/drivers/libimagequant/blur.h
@@ -0,0 +1,4 @@
+
+LIQ_PRIVATE void liq_blur(unsigned char *src, unsigned char *tmp, unsigned char *dst, unsigned int width, unsigned int height, unsigned int size);
+LIQ_PRIVATE void liq_max3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height);
+LIQ_PRIVATE void liq_min3(unsigned char *src, unsigned char *dst, unsigned int width, unsigned int height);
diff --git a/src/drivers/libimagequant/configure b/src/drivers/libimagequant/configure
new file mode 100755
index 0000000..23f84d7
--- /dev/null
+++ b/src/drivers/libimagequant/configure
@@ -0,0 +1,205 @@
+#!/usr/bin/env bash
+
+CONFIG="config.mk"
+PREFIX="/usr/local"
+VERSION=$(grep LIQ_VERSION_STRING libimagequant.h | grep -Eo "2\.[0-9.]+")
+
+DEBUG=
+SSE=auto
+OPENMP=
+EXTRA_CFLAGS=
+EXTRA_LDFLAGS=
+
+# make gcc default compiler unless CC is already set
+CC=${CC:-gcc}
+
+help() {
+ printf "%4s %s\n" "" "$1"
+}
+
+for i in "$@"; do
+ case $i in
+ --help)
+ echo
+ help "--prefix= installation directory [$PREFIX]"
+ help "--extra-cflags= append to CFLAGS"
+ help "--extra-ldflags= append to LDFLAGS"
+ echo
+ help "--enable-debug"
+ help "--enable-sse/--disable-sse enable/disable SSE instructions"
+ echo
+ help "--with-openmp compile with multicore support"
+ echo
+ exit 0
+ ;;
+ # Can be set before or after configure. Latter overrides former.
+ CC=*)
+ CC=${i#*=}
+ ;;
+ CFLAGS=*)
+ CFLAGS=${i#*=}
+ ;;
+ LDFLAGS=*)
+ LDFLAGS=${i#*=}
+ ;;
+ --enable-debug)
+ DEBUG=1
+ ;;
+ --enable-sse)
+ SSE=1
+ ;;
+ --disable-sse)
+ SSE=0
+ ;;
+ --with-openmp)
+ OPENMP=1
+ ;;
+ --prefix=*)
+ PREFIX=${i#*=}
+ ;;
+ # can be used multiple times or in quotes to set multiple flags
+ --extra-cflags=*)
+ EXTRA_CFLAGS="$EXTRA_CFLAGS ${i#*=}"
+ ;;
+ --extra-ldflags=*)
+ EXTRA_LDFLAGS="$EXTRA_LDFLAGS ${i#*=}"
+ ;;
+ *)
+ echo "error: unknown switch ${i%%=*}"
+ exit 1
+ ;;
+ esac
+done
+
+# If someone runs sudo make install as very first command, and configure later,
+# $CONFIG cannot be overwritten, and must be deleted before continuing.
+if [[ -f "$CONFIG" && ! -w "$CONFIG" ]]; then
+ echo "Cannot overwrite file $CONFIG! Please delete it."
+ exit 1
+fi
+
+cflags() {
+ CFLAGS="$CFLAGS $1"
+}
+
+lflags() {
+ LDFLAGS="$LDFLAGS $1"
+}
+
+status() {
+ printf "%10s: %s\n" "$1" "$2"
+}
+
+# Append to CFLAGS if compiler supports flag, with optional prerequisite.
+# Fails on errors and warnings.
+conditional_cflags() {
+ if [ -z "$("$CC" -xc -S -o /dev/null $2 $1 <(echo) 2>&1)" ]; then
+ cflags "$1"
+ fi
+}
+
+error() {
+ status "$1" "error ... $2"
+ echo
+ exit 1
+}
+
+echo
+
+# basic check
+if ! "$CC" -xc -std=c99 <(echo "int main(){}") -o /dev/null &> /dev/null; then
+ error "Compiler" "$CC is no C compiler"
+fi
+
+status "Compiler" "$CC"
+
+# init flags
+CFLAGS=${CFLAGS:--O3 -fno-math-errno -funroll-loops -fomit-frame-pointer -Wall}
+cflags "-std=c99 -I."
+
+# DEBUG
+if [ -z "$DEBUG" ]; then
+ cflags "-DNDEBUG"
+ status "Debug" "no"
+else
+ cflags "-g"
+ status "Debug" "yes"
+fi
+
+# SSE
+if [ "$SSE" = 'auto' ]; then
+ if [[ "$(uname -m)" =~ (amd|x86_)64 ||
+ "$(grep -E -m1 "^flags" /proc/cpuinfo)" =~ "sse" ]]; then
+ SSE=1
+ fi
+fi
+
+if [ "$SSE" -eq 1 ]; then
+ status "SSE" "yes"
+ cflags "-DUSE_SSE=1"
+ cflags "-msse"
+ # Silence a later ICC warning due to -msse working slightly different.
+ conditional_cflags "-wd10121"
+ # Must be set explicitly for GCC on x86_32. Other compilers imply it.
+ conditional_cflags "-mfpmath=sse" "-msse"
+elif [ "$SSE" -eq 0 ]; then
+ status "SSE" "no"
+ cflags "-DUSE_SSE=0"
+fi
+
+# OpenMP
+if [ -n "$OPENMP" ]; then
+ if [[ "$("$CC" -xc -E -fopenmp <(echo -e \
+ "#ifdef _OPENMP
+ #include <omp.h>
+ #endif") 2>&1)" =~ "omp_get_thread_num" ]]; then
+ cflags "-fopenmp"
+ lflags "-fopenmp"
+ status "OpenMP" "yes"
+ else
+ error "OpenMP" "not supported by compiler"
+ fi
+else
+ # silence warnings about omp pragmas
+ cflags "-Wno-unknown-pragmas"
+ conditional_cflags "-wd3180" # ICC
+ status "OpenMP" "no"
+fi
+
+echo
+
+# As of GCC 4.5, 387 fp math is significantly slower in C99 mode without this.
+# Note: CPUs without SSE2 use 387 for doubles, even when SSE fp math is set.
+conditional_cflags "-fexcess-precision=fast"
+
+# Intel C++ Compiler
+
+# ICC does usually only produce fast(er) code when it can optimize to the full
+# capabilites of the (Intel) CPU. This is equivalent to -march=native for GCC.
+conditional_cflags "-xHOST"
+
+# Disable unsafe fp optimizations and enforce fp precision as set in the source.
+conditional_cflags "-fp-model source"
+
+# Silence a gold linker warning about string misalignment.
+conditional_cflags "-falign-stack=maintain-16-byte"
+
+lflags "-lm" # Ubuntu requires this library last, issue #38
+
+if [ -n "$EXTRA_CFLAGS" ]; then
+ cflags "$EXTRA_CFLAGS"
+fi
+
+if [ -n "$EXTRA_LDFLAGS" ]; then
+ lflags "$EXTRA_LDFLAGS"
+fi
+
+# Overwrite previous configuration.
+echo "
+# auto-generated by configure
+PREFIX = $PREFIX
+VERSION = $VERSION
+CC = $CC
+CFLAGS = $CFLAGS
+LDFLAGS = $LDFLAGS
+" > $CONFIG
diff --git a/src/drivers/libimagequant/libimagequant.c b/src/drivers/libimagequant/libimagequant.c
new file mode 100644
index 0000000..5812e37
--- /dev/null
+++ b/src/drivers/libimagequant/libimagequant.c
@@ -0,0 +1,1648 @@
+/* pngquant.c - quantize the colors in an alphamap down to a specified number
+**
+** Copyright (C) 1989, 1991 by Jef Poskanzer.
+** Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by
+** Stefan Schneider.
+** © 2009-2013 by Kornel Lesinski.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <limits.h>
+
+#if !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900L) && !(defined(_MSC_VER) && _MSC_VER >= 1800)
+#error "This program requires C99, e.g. -std=c99 switch in GCC or it requires MSVC 18.0 or higher."
+#error "Ignore torrent of syntax errors that may follow. It's only because compiler is set to use too old C version."
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#else
+#define omp_get_max_threads() 1
+#define omp_get_thread_num() 0
+#endif
+
+#include "libimagequant.h"
+
+#include "pam.h"
+#include "mediancut.h"
+#include "nearest.h"
+#include "blur.h"
+#include "viter.h"
+
+#define LIQ_HIGH_MEMORY_LIMIT (1<<26) /* avoid allocating buffers larger than 64MB */
+
+// each structure has a pointer as a unique identifier that allows type checking at run time
+static const char *const liq_attr_magic = "liq_attr", *const liq_image_magic = "liq_image",
+ *const liq_result_magic = "liq_result", *const liq_remapping_result_magic = "liq_remapping_result",
+ *const liq_freed_magic = "free";
+#define CHECK_STRUCT_TYPE(attr, kind) liq_crash_if_invalid_handle_pointer_given((const liq_attr*)attr, kind ## _magic)
+#define CHECK_USER_POINTER(ptr) liq_crash_if_invalid_pointer_given(ptr)
+
+struct liq_attr {
+ const char *magic_header;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+
+ double target_mse, max_mse, voronoi_iteration_limit;
+ float min_opaque_val;
+ unsigned int max_colors, max_histogram_entries;
+ unsigned int min_posterization_output /* user setting */, min_posterization_input /* speed setting */;
+ unsigned int voronoi_iterations, feedback_loop_trials;
+ bool last_index_transparent, use_contrast_maps, use_dither_map, fast_palette;
+ unsigned int speed;
+ liq_log_callback_function *log_callback;
+ void *log_callback_user_info;
+ liq_log_flush_callback_function *log_flush_callback;
+ void *log_flush_callback_user_info;
+};
+
+struct liq_image {
+ const char *magic_header;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+
+ f_pixel *f_pixels;
+ rgba_pixel **rows;
+ double gamma;
+ unsigned int width, height;
+ unsigned char *noise, *edges, *dither_map;
+ rgba_pixel *pixels, *temp_row;
+ f_pixel *temp_f_row;
+ liq_image_get_rgba_row_callback *row_callback;
+ void *row_callback_user_info;
+ float min_opaque_val;
+ bool free_pixels, free_rows, free_rows_internal;
+};
+
+typedef struct liq_remapping_result {
+ const char *magic_header;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+
+ unsigned char *pixels;
+ colormap *palette;
+ liq_palette int_palette;
+ double gamma, palette_error;
+ float dither_level;
+ bool use_dither_map;
+} liq_remapping_result;
+
+struct liq_result {
+ const char *magic_header;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+
+ liq_remapping_result *remapping;
+ colormap *palette;
+ liq_palette int_palette;
+ float dither_level;
+ double gamma, palette_error;
+ int min_posterization_output;
+ bool use_dither_map, fast_palette;
+};
+
+static liq_result *pngquant_quantize(histogram *hist, const liq_attr *options, double gamma);
+static void modify_alpha(liq_image *input_image, rgba_pixel *const row_pixels);
+static void contrast_maps(liq_image *image);
+static histogram *get_histogram(liq_image *input_image, const liq_attr *options);
+static const rgba_pixel *liq_image_get_row_rgba(liq_image *input_image, unsigned int row);
+static const f_pixel *liq_image_get_row_f(liq_image *input_image, unsigned int row);
+static void liq_remapping_result_destroy(liq_remapping_result *result);
+
+static void liq_verbose_printf(const liq_attr *context, const char *fmt, ...)
+{
+ if (context->log_callback) {
+ va_list va;
+ va_start(va, fmt);
+ int required_space = vsnprintf(NULL, 0, fmt, va)+1; // +\0
+ va_end(va);
+
+ char buf[required_space];
+ va_start(va, fmt);
+ vsnprintf(buf, required_space, fmt, va);
+ va_end(va);
+
+ context->log_callback(context, buf, context->log_callback_user_info);
+ }
+}
+
+inline static void verbose_print(const liq_attr *attr, const char *msg)
+{
+ if (attr->log_callback) {
+ attr->log_callback(attr, msg, attr->log_callback_user_info);
+ }
+}
+
+static void liq_verbose_printf_flush(liq_attr *attr)
+{
+ if (attr->log_flush_callback) {
+ attr->log_flush_callback(attr, attr->log_flush_callback_user_info);
+ }
+}
+
+#if USE_SSE
+inline static bool is_sse_available()
+{
+#if (defined(__x86_64__) || defined(__amd64))
+ return true;
+#else
+ int a,b,c,d;
+ cpuid(1, a, b, c, d);
+ return d & (1<<25); // edx bit 25 is set when SSE is present
+#endif
+}
+#endif
+
+/* make it clear in backtrace when user-supplied handle points to invalid memory */
+NEVER_INLINE LIQ_EXPORT bool liq_crash_if_invalid_handle_pointer_given(const liq_attr *user_supplied_pointer, const char *const expected_magic_header);
+LIQ_EXPORT bool liq_crash_if_invalid_handle_pointer_given(const liq_attr *user_supplied_pointer, const char *const expected_magic_header)
+{
+ if (!user_supplied_pointer) {
+ return false;
+ }
+
+ if (user_supplied_pointer->magic_header == liq_freed_magic) {
+ fprintf(stderr, "%s used after being freed", expected_magic_header);
+ // this is not normal error handling, this is programmer error that should crash the program.
+ // program cannot safely continue if memory has been used after it's been freed.
+ // abort() is nasty, but security vulnerability may be worse.
+ abort();
+ }
+
+ return user_supplied_pointer->magic_header == expected_magic_header;
+}
+
+NEVER_INLINE LIQ_EXPORT bool liq_crash_if_invalid_pointer_given(void *pointer);
+LIQ_EXPORT bool liq_crash_if_invalid_pointer_given(void *pointer)
+{
+ if (!pointer) {
+ return false;
+ }
+ // Force a read from the given (potentially invalid) memory location in order to check early whether this crashes the program or not.
+ // It doesn't matter what value is read, the code here is just to shut the compiler up about unused read.
+ char test_access = *((volatile char *)pointer);
+ return test_access || true;
+}
+
+static void liq_log_error(const liq_attr *attr, const char *msg) {
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return;
+ liq_verbose_printf(attr, " error: %s", msg);
+}
+
+static double quality_to_mse(long quality)
+{
+ if (quality == 0) {
+ return MAX_DIFF;
+ }
+ if (quality == 100) {
+ return 0;
+ }
+
+ // curve fudged to be roughly similar to quality of libjpeg
+ // except lowest 10 for really low number of colors
+ const double extra_low_quality_fudge = MAX(0,0.016/(0.001+quality) - 0.001);
+ return extra_low_quality_fudge + 2.5/pow(210.0 + quality, 1.2) * (100.1-quality)/100.0;
+}
+
+static unsigned int mse_to_quality(double mse)
+{
+ for(int i=100; i > 0; i--) {
+ if (mse <= quality_to_mse(i) + 0.000001) { // + epsilon for floating point errors
+ return i;
+ }
+ }
+ return 0;
+}
+
+LIQ_EXPORT liq_error liq_set_quality(liq_attr* attr, int minimum, int target)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER;
+ if (target < 0 || target > 100 || target < minimum || minimum < 0) return LIQ_VALUE_OUT_OF_RANGE;
+
+ attr->target_mse = quality_to_mse(target);
+ attr->max_mse = quality_to_mse(minimum);
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_get_min_quality(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+ return mse_to_quality(attr->max_mse);
+}
+
+LIQ_EXPORT int liq_get_max_quality(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+ return mse_to_quality(attr->target_mse);
+}
+
+
+LIQ_EXPORT liq_error liq_set_max_colors(liq_attr* attr, int colors)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER;
+ if (colors < 2 || colors > 256) return LIQ_VALUE_OUT_OF_RANGE;
+
+ attr->max_colors = colors;
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_get_max_colors(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+
+ return attr->max_colors;
+}
+
+LIQ_EXPORT liq_error liq_set_min_posterization(liq_attr *attr, int bits)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER;
+ if (bits < 0 || bits > 4) return LIQ_VALUE_OUT_OF_RANGE;
+
+ attr->min_posterization_output = bits;
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_get_min_posterization(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+
+ return attr->min_posterization_output;
+}
+
+LIQ_EXPORT liq_error liq_set_speed(liq_attr* attr, int speed)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER;
+ if (speed < 1 || speed > 10) return LIQ_VALUE_OUT_OF_RANGE;
+
+ int iterations = MAX(8-speed,0); iterations += iterations * iterations/2;
+ attr->voronoi_iterations = iterations;
+ attr->voronoi_iteration_limit = 1.0/(double)(1<<(23-speed));
+ attr->feedback_loop_trials = MAX(56-9*speed, 0);
+
+ attr->max_histogram_entries = (1<<17) + (1<<18)*(10-speed);
+ attr->min_posterization_input = (speed >= 8) ? 1 : 0;
+ attr->fast_palette = (speed >= 7);
+ attr->use_dither_map = (speed <= (omp_get_max_threads() > 1 ? 7 : 5)); // parallelized dither map might speed up floyd remapping
+ attr->use_contrast_maps = (speed <= 7) || attr->use_dither_map;
+ attr->speed = speed;
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_get_speed(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+
+ return attr->speed;
+}
+
+LIQ_EXPORT liq_error liq_set_output_gamma(liq_result* res, double gamma)
+{
+ if (!CHECK_STRUCT_TYPE(res, liq_result)) return LIQ_INVALID_POINTER;
+ if (gamma <= 0 || gamma >= 1.0) return LIQ_VALUE_OUT_OF_RANGE;
+
+ if (res->remapping) {
+ liq_remapping_result_destroy(res->remapping);
+ res->remapping = NULL;
+ }
+
+ res->gamma = gamma;
+ return LIQ_OK;
+}
+
+LIQ_EXPORT liq_error liq_set_min_opacity(liq_attr* attr, int min)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return LIQ_INVALID_POINTER;
+ if (min < 0 || min > 255) return LIQ_VALUE_OUT_OF_RANGE;
+
+ attr->min_opaque_val = (double)min/255.0;
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_get_min_opacity(const liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return -1;
+
+ return MIN(255, 256.0 * attr->min_opaque_val);
+}
+
+LIQ_EXPORT void liq_set_last_index_transparent(liq_attr* attr, int is_last)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return;
+
+ attr->last_index_transparent = !!is_last;
+}
+
+LIQ_EXPORT void liq_set_log_callback(liq_attr *attr, liq_log_callback_function *callback, void* user_info)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return;
+
+ liq_verbose_printf_flush(attr);
+ attr->log_callback = callback;
+ attr->log_callback_user_info = user_info;
+}
+
+LIQ_EXPORT void liq_set_log_flush_callback(liq_attr *attr, liq_log_flush_callback_function *callback, void* user_info)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return;
+
+ attr->log_flush_callback = callback;
+ attr->log_flush_callback_user_info = user_info;
+}
+
+LIQ_EXPORT liq_attr* liq_attr_create()
+{
+ return liq_attr_create_with_allocator(NULL, NULL);
+}
+
+LIQ_EXPORT void liq_attr_destroy(liq_attr *attr)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) {
+ return;
+ }
+
+ liq_verbose_printf_flush(attr);
+
+ attr->magic_header = liq_freed_magic;
+ attr->free(attr);
+}
+
+LIQ_EXPORT liq_attr* liq_attr_copy(liq_attr *orig)
+{
+ if (!CHECK_STRUCT_TYPE(orig, liq_attr)) {
+ return NULL;
+ }
+
+ liq_attr *attr = orig->malloc(sizeof(liq_attr));
+ if (!attr) return NULL;
+ *attr = *orig;
+ return attr;
+}
+
+static void *liq_aligned_malloc(size_t size)
+{
+ unsigned char *ptr = malloc(size + 16);
+ if (!ptr) {
+ return NULL;
+ }
+
+ uintptr_t offset = 16 - ((uintptr_t)ptr & 15); // also reserves 1 byte for ptr[-1]
+ ptr += offset;
+ assert(0 == (((uintptr_t)ptr) & 15));
+ ptr[-1] = offset ^ 0x59; // store how much pointer was shifted to get the original for free()
+ return ptr;
+}
+
+static void liq_aligned_free(void *inptr)
+{
+ unsigned char *ptr = inptr;
+ size_t offset = ptr[-1] ^ 0x59;
+ assert(offset > 0 && offset <= 16);
+ free(ptr - offset);
+}
+
+LIQ_EXPORT liq_attr* liq_attr_create_with_allocator(void* (*custom_malloc)(size_t), void (*custom_free)(void*))
+{
+#if USE_SSE
+ if (!is_sse_available()) {
+ return NULL;
+ }
+#endif
+ if (!custom_malloc && !custom_free) {
+ custom_malloc = liq_aligned_malloc;
+ custom_free = liq_aligned_free;
+ } else if (!custom_malloc != !custom_free) {
+ return NULL; // either specify both or none
+ }
+
+ liq_attr *attr = custom_malloc(sizeof(liq_attr));
+ if (!attr) return NULL;
+ *attr = (liq_attr) {
+ .magic_header = liq_attr_magic,
+ .malloc = custom_malloc,
+ .free = custom_free,
+ .max_colors = 256,
+ .min_opaque_val = 1, // whether preserve opaque colors for IE (1.0=no, does not affect alpha)
+ .last_index_transparent = false, // puts transparent color at last index. This is workaround for blu-ray subtitles.
+ .target_mse = 0,
+ .max_mse = MAX_DIFF,
+ };
+ liq_set_speed(attr, 3);
+ return attr;
+}
+
+static bool liq_image_use_low_memory(liq_image *img)
+{
+ img->temp_f_row = img->malloc(sizeof(img->f_pixels[0]) * img->width * omp_get_max_threads());
+ return img->temp_f_row != NULL;
+}
+
+static bool liq_image_should_use_low_memory(liq_image *img, const bool low_memory_hint)
+{
+ return img->width * img->height > (low_memory_hint ? LIQ_HIGH_MEMORY_LIMIT/8 : LIQ_HIGH_MEMORY_LIMIT) / sizeof(f_pixel); // Watch out for integer overflow
+}
+
+static liq_image *liq_image_create_internal(liq_attr *attr, rgba_pixel* rows[], liq_image_get_rgba_row_callback *row_callback, void *row_callback_user_info, int width, int height, double gamma)
+{
+ if (gamma < 0 || gamma > 1.0) {
+ liq_log_error(attr, "gamma must be >= 0 and <= 1 (try 1/gamma instead)");
+ return NULL;
+ }
+
+ if (!rows && !row_callback) {
+ liq_log_error(attr, "missing row data");
+ return NULL;
+ }
+
+ liq_image *img = attr->malloc(sizeof(liq_image));
+ if (!img) return NULL;
+ *img = (liq_image){
+ .magic_header = liq_image_magic,
+ .malloc = attr->malloc,
+ .free = attr->free,
+ .width = width, .height = height,
+ .gamma = gamma ? gamma : 0.45455,
+ .rows = rows,
+ .row_callback = row_callback,
+ .row_callback_user_info = row_callback_user_info,
+ .min_opaque_val = attr->min_opaque_val,
+ };
+
+ if (!rows || attr->min_opaque_val < 1.f) {
+ img->temp_row = attr->malloc(sizeof(img->temp_row[0]) * width * omp_get_max_threads());
+ if (!img->temp_row) return NULL;
+ }
+
+ // if image is huge or converted pixels are not likely to be reused then don't cache converted pixels
+ if (liq_image_should_use_low_memory(img, !img->temp_row && !attr->use_contrast_maps && !attr->use_dither_map)) {
+ verbose_print(attr, " conserving memory");
+ if (!liq_image_use_low_memory(img)) return NULL;
+ }
+
+ if (img->min_opaque_val < 1.f) {
+ verbose_print(attr, " Working around IE6 bug by making image less transparent...");
+ }
+
+ return img;
+}
+
+LIQ_EXPORT liq_error liq_image_set_memory_ownership(liq_image *img, int ownership_flags)
+{
+ if (!CHECK_STRUCT_TYPE(img, liq_image)) return LIQ_INVALID_POINTER;
+ if (!img->rows || !ownership_flags || (ownership_flags & ~(LIQ_OWN_ROWS|LIQ_OWN_PIXELS))) {
+ return LIQ_VALUE_OUT_OF_RANGE;
+ }
+
+ if (ownership_flags & LIQ_OWN_ROWS) {
+ if (img->free_rows_internal) return LIQ_VALUE_OUT_OF_RANGE;
+ img->free_rows = true;
+ }
+
+ if (ownership_flags & LIQ_OWN_PIXELS) {
+ img->free_pixels = true;
+ if (!img->pixels) {
+ // for simplicity of this API there's no explicit bitmap argument,
+ // so the row with the lowest address is assumed to be at the start of the bitmap
+ img->pixels = img->rows[0];
+ for(unsigned int i=1; i < img->height; i++) {
+ img->pixels = MIN(img->pixels, img->rows[i]);
+ }
+ }
+ }
+
+ return LIQ_OK;
+}
+
+static bool check_image_size(const liq_attr *attr, const int width, const int height)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) {
+ return false;
+ }
+
+ if (width <= 0 || height <= 0) {
+ liq_log_error(attr, "width and height must be > 0");
+ return false;
+ }
+ if (width > INT_MAX/height) {
+ liq_log_error(attr, "image too large");
+ return false;
+ }
+ return true;
+}
+
+LIQ_EXPORT liq_image *liq_image_create_custom(liq_attr *attr, liq_image_get_rgba_row_callback *row_callback, void* user_info, int width, int height, double gamma)
+{
+ if (!check_image_size(attr, width, height)) {
+ return NULL;
+ }
+ return liq_image_create_internal(attr, NULL, row_callback, user_info, width, height, gamma);
+}
+
+LIQ_EXPORT liq_image *liq_image_create_rgba_rows(liq_attr *attr, void* rows[], int width, int height, double gamma)
+{
+ if (!check_image_size(attr, width, height)) {
+ return NULL;
+ }
+
+ for(int i=0; i < height; i++) {
+ if (!CHECK_USER_POINTER(rows+i) || !CHECK_USER_POINTER(rows[i])) {
+ liq_log_error(attr, "invalid row pointers");
+ return NULL;
+ }
+ }
+ return liq_image_create_internal(attr, (rgba_pixel**)rows, NULL, NULL, width, height, gamma);
+}
+
+LIQ_EXPORT liq_image *liq_image_create_rgba(liq_attr *attr, void* bitmap, int width, int height, double gamma)
+{
+ if (!check_image_size(attr, width, height)) {
+ return NULL;
+ }
+ if (!CHECK_USER_POINTER(bitmap)) {
+ liq_log_error(attr, "invalid bitmap pointer");
+ return NULL;
+ }
+
+ rgba_pixel *pixels = bitmap;
+ rgba_pixel **rows = attr->malloc(sizeof(rows[0])*height);
+ if (!rows) return NULL;
+
+ for(int i=0; i < height; i++) {
+ rows[i] = pixels + width * i;
+ }
+
+ liq_image *image = liq_image_create_internal(attr, rows, NULL, NULL, width, height, gamma);
+ image->free_rows = true;
+ image->free_rows_internal = true;
+ return image;
+}
+
+NEVER_INLINE LIQ_EXPORT void liq_executing_user_callback(liq_image_get_rgba_row_callback *callback, liq_color *temp_row, int row, int width, void *user_info);
+LIQ_EXPORT void liq_executing_user_callback(liq_image_get_rgba_row_callback *callback, liq_color *temp_row, int row, int width, void *user_info)
+{
+ assert(callback);
+ assert(temp_row);
+ callback(temp_row, row, width, user_info);
+}
+
+inline static bool liq_image_can_use_rows(liq_image *img)
+{
+ const bool iebug = img->min_opaque_val < 1.f;
+ return (img->rows && !iebug);
+}
+
+static const rgba_pixel *liq_image_get_row_rgba(liq_image *img, unsigned int row)
+{
+ if (liq_image_can_use_rows(img)) {
+ return img->rows[row];
+ }
+
+ assert(img->temp_row);
+ rgba_pixel *temp_row = img->temp_row + img->width * omp_get_thread_num();
+ if (img->rows) {
+ memcpy(temp_row, img->rows[row], img->width * sizeof(temp_row[0]));
+ } else {
+ liq_executing_user_callback(img->row_callback, (liq_color*)temp_row, row, img->width, img->row_callback_user_info);
+ }
+
+ if (img->min_opaque_val < 1.f) modify_alpha(img, temp_row);
+ return temp_row;
+}
+
+static void convert_row_to_f(liq_image *img, f_pixel *row_f_pixels, const unsigned int row, const float gamma_lut[])
+{
+ assert(row_f_pixels);
+ assert(!USE_SSE || 0 == ((uintptr_t)row_f_pixels & 15));
+
+ const rgba_pixel *const row_pixels = liq_image_get_row_rgba(img, row);
+
+ for(unsigned int col=0; col < img->width; col++) {
+ row_f_pixels[col] = to_f(gamma_lut, row_pixels[col]);
+ }
+}
+
+static const f_pixel *liq_image_get_row_f(liq_image *img, unsigned int row)
+{
+ if (!img->f_pixels) {
+ if (img->temp_f_row) {
+ float gamma_lut[256];
+ to_f_set_gamma(gamma_lut, img->gamma);
+ f_pixel *row_for_thread = img->temp_f_row + img->width * omp_get_thread_num();
+ convert_row_to_f(img, row_for_thread, row, gamma_lut);
+ return row_for_thread;
+ }
+
+ assert(omp_get_thread_num() == 0);
+ if (!liq_image_should_use_low_memory(img, false)) {
+ img->f_pixels = img->malloc(sizeof(img->f_pixels[0]) * img->width * img->height);
+ }
+ if (!img->f_pixels) {
+ if (!liq_image_use_low_memory(img)) return NULL;
+ return liq_image_get_row_f(img, row);
+ }
+
+ float gamma_lut[256];
+ to_f_set_gamma(gamma_lut, img->gamma);
+ for(unsigned int i=0; i < img->height; i++) {
+ convert_row_to_f(img, &img->f_pixels[i*img->width], i, gamma_lut);
+ }
+ }
+ return img->f_pixels + img->width * row;
+}
+
+LIQ_EXPORT int liq_image_get_width(const liq_image *input_image)
+{
+ if (!CHECK_STRUCT_TYPE(input_image, liq_image)) return -1;
+ return input_image->width;
+}
+
+LIQ_EXPORT int liq_image_get_height(const liq_image *input_image)
+{
+ if (!CHECK_STRUCT_TYPE(input_image, liq_image)) return -1;
+ return input_image->height;
+}
+
+typedef void free_func(void*);
+
+free_func *get_default_free_func(liq_image *img)
+{
+ // When default allocator is used then user-supplied pointers must be freed with free()
+ if (img->free_rows_internal || img->free != liq_aligned_free) {
+ return img->free;
+ }
+ return free;
+}
+
+static void liq_image_free_rgba_source(liq_image *input_image)
+{
+ if (input_image->free_pixels && input_image->pixels) {
+ get_default_free_func(input_image)(input_image->pixels);
+ input_image->pixels = NULL;
+ }
+
+ if (input_image->free_rows && input_image->rows) {
+ get_default_free_func(input_image)(input_image->rows);
+ input_image->rows = NULL;
+ }
+}
+
+LIQ_EXPORT void liq_image_destroy(liq_image *input_image)
+{
+ if (!CHECK_STRUCT_TYPE(input_image, liq_image)) return;
+
+ liq_image_free_rgba_source(input_image);
+
+ if (input_image->noise) {
+ input_image->free(input_image->noise);
+ }
+
+ if (input_image->edges) {
+ input_image->free(input_image->edges);
+ }
+
+ if (input_image->dither_map) {
+ input_image->free(input_image->dither_map);
+ }
+
+ if (input_image->f_pixels) {
+ input_image->free(input_image->f_pixels);
+ }
+
+ if (input_image->temp_row) {
+ input_image->free(input_image->temp_row);
+ }
+
+ if (input_image->temp_f_row) {
+ input_image->free(input_image->temp_f_row);
+ }
+
+ input_image->magic_header = liq_freed_magic;
+ input_image->free(input_image);
+}
+
+LIQ_EXPORT liq_result *liq_quantize_image(liq_attr *attr, liq_image *img)
+{
+ if (!CHECK_STRUCT_TYPE(attr, liq_attr)) return NULL;
+ if (!CHECK_STRUCT_TYPE(img, liq_image)) {
+ liq_log_error(attr, "invalid image pointer");
+ return NULL;
+ }
+
+ histogram *hist = get_histogram(img, attr);
+ if (!hist) {
+ return NULL;
+ }
+
+ liq_result *result = pngquant_quantize(hist, attr, img->gamma);
+
+ pam_freeacolorhist(hist);
+ return result;
+}
+
+LIQ_EXPORT liq_error liq_set_dithering_level(liq_result *res, float dither_level)
+{
+ if (!CHECK_STRUCT_TYPE(res, liq_result)) return LIQ_INVALID_POINTER;
+
+ if (res->remapping) {
+ liq_remapping_result_destroy(res->remapping);
+ res->remapping = NULL;
+ }
+
+ if (res->dither_level < 0 || res->dither_level > 1.0f) return LIQ_VALUE_OUT_OF_RANGE;
+ res->dither_level = dither_level;
+ return LIQ_OK;
+}
+
+static liq_remapping_result *liq_remapping_result_create(liq_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) {
+ return NULL;
+ }
+
+ liq_remapping_result *res = result->malloc(sizeof(liq_remapping_result));
+ if (!res) return NULL;
+ *res = (liq_remapping_result) {
+ .magic_header = liq_remapping_result_magic,
+ .malloc = result->malloc,
+ .free = result->free,
+ .dither_level = result->dither_level,
+ .use_dither_map = result->use_dither_map,
+ .palette_error = result->palette_error,
+ .gamma = result->gamma,
+ .palette = pam_duplicate_colormap(result->palette),
+ };
+ return res;
+}
+
+LIQ_EXPORT double liq_get_output_gamma(const liq_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) return -1;
+
+ return result->gamma;
+}
+
+static void liq_remapping_result_destroy(liq_remapping_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_remapping_result)) return;
+
+ if (result->palette) pam_freecolormap(result->palette);
+ if (result->pixels) result->free(result->pixels);
+
+ result->magic_header = liq_freed_magic;
+ result->free(result);
+}
+
+LIQ_EXPORT void liq_result_destroy(liq_result *res)
+{
+ if (!CHECK_STRUCT_TYPE(res, liq_result)) return;
+
+ memset(&res->int_palette, 0, sizeof(liq_palette));
+
+ if (res->remapping) {
+ memset(&res->remapping->int_palette, 0, sizeof(liq_palette));
+ liq_remapping_result_destroy(res->remapping);
+ }
+
+ pam_freecolormap(res->palette);
+
+ res->magic_header = liq_freed_magic;
+ res->free(res);
+}
+
+LIQ_EXPORT double liq_get_quantization_error(liq_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) return -1;
+
+ if (result->palette_error >= 0) {
+ return result->palette_error*65536.0/6.0;
+ }
+
+ if (result->remapping && result->remapping->palette_error >= 0) {
+ return result->remapping->palette_error*65536.0/6.0;
+ }
+
+ return result->palette_error;
+}
+
+LIQ_EXPORT int liq_get_quantization_quality(liq_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) return -1;
+
+ if (result->palette_error >= 0) {
+ return mse_to_quality(result->palette_error);
+ }
+
+ if (result->remapping && result->remapping->palette_error >= 0) {
+ return mse_to_quality(result->remapping->palette_error);
+ }
+
+ return result->palette_error;
+}
+
+static int compare_popularity(const void *ch1, const void *ch2)
+{
+ const float v1 = ((const colormap_item*)ch1)->popularity;
+ const float v2 = ((const colormap_item*)ch2)->popularity;
+ return v1 > v2 ? -1 : 1;
+}
+
+static void sort_palette_qsort(colormap *map, int start, int nelem)
+{
+ qsort(map->palette + start, nelem, sizeof(map->palette[0]), compare_popularity);
+}
+
+#define SWAP_PALETTE(map, a,b) { \
+ const colormap_item tmp = (map)->palette[(a)]; \
+ (map)->palette[(a)] = (map)->palette[(b)]; \
+ (map)->palette[(b)] = tmp; }
+
+static void sort_palette(colormap *map, const liq_attr *options)
+{
+ /*
+ ** Step 3.5 [GRR]: remap the palette colors so that all entries with
+ ** the maximal alpha value (i.e., fully opaque) are at the end and can
+ ** therefore be omitted from the tRNS chunk.
+ */
+ if (options->last_index_transparent) {
+ for(unsigned int i=0; i < map->colors; i++) {
+ if (map->palette[i].acolor.a < 1.0/256.0) {
+ const unsigned int old = i, transparent_dest = map->colors-1;
+
+ SWAP_PALETTE(map, transparent_dest, old);
+
+ /* colors sorted by popularity make pngs slightly more compressible */
+ sort_palette_qsort(map, 0, map->colors-1);
+ return;
+ }
+ }
+ }
+ /* move transparent colors to the beginning to shrink trns chunk */
+ unsigned int num_transparent=0;
+ for(unsigned int i=0; i < map->colors; i++) {
+ if (map->palette[i].acolor.a < 255.0/256.0) {
+ // current transparent color is swapped with earlier opaque one
+ if (i != num_transparent) {
+ SWAP_PALETTE(map, num_transparent, i);
+ i--;
+ }
+ num_transparent++;
+ }
+ }
+
+ liq_verbose_printf(options, " eliminated opaque tRNS-chunk entries...%d entr%s transparent", num_transparent, (num_transparent == 1)? "y" : "ies");
+
+ /* colors sorted by popularity make pngs slightly more compressible
+ * opaque and transparent are sorted separately
+ */
+ sort_palette_qsort(map, 0, num_transparent);
+ sort_palette_qsort(map, num_transparent, map->colors-num_transparent);
+
+ if (map->colors > 16) {
+ SWAP_PALETTE(map, 7, 1); // slightly improves compression
+ SWAP_PALETTE(map, 8, 2);
+ SWAP_PALETTE(map, 9, 3);
+ }
+}
+
+inline static unsigned int posterize_channel(unsigned int color, unsigned int bits)
+{
+ return (color & ~((1<<bits)-1)) | (color >> (8-bits));
+}
+
+static void set_rounded_palette(liq_palette *const dest, colormap *const map, const double gamma, unsigned int posterize)
+{
+ float gamma_lut[256];
+ to_f_set_gamma(gamma_lut, gamma);
+
+ dest->count = map->colors;
+ for(unsigned int x = 0; x < map->colors; ++x) {
+ rgba_pixel px = to_rgb(gamma, map->palette[x].acolor);
+
+ px.r = posterize_channel(px.r, posterize);
+ px.g = posterize_channel(px.g, posterize);
+ px.b = posterize_channel(px.b, posterize);
+ px.a = posterize_channel(px.a, posterize);
+
+ map->palette[x].acolor = to_f(gamma_lut, px); /* saves rounding error introduced by to_rgb, which makes remapping & dithering more accurate */
+
+ if (!px.a) {
+ px.r = 'L'; px.g = 'i'; px.b = 'q';
+ }
+
+ dest->entries[x] = (liq_color){.r=px.r,.g=px.g,.b=px.b,.a=px.a};
+ }
+}
+
+LIQ_EXPORT const liq_palette *liq_get_palette(liq_result *result)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) return NULL;
+
+ if (result->remapping && result->remapping->int_palette.count) {
+ return &result->remapping->int_palette;
+ }
+
+ if (!result->int_palette.count) {
+ set_rounded_palette(&result->int_palette, result->palette, result->gamma, result->min_posterization_output);
+ }
+ return &result->int_palette;
+}
+
+static float remap_to_palette(liq_image *const input_image, unsigned char *const *const output_pixels, colormap *const map, const bool fast)
+{
+ const int rows = input_image->height;
+ const unsigned int cols = input_image->width;
+ const float min_opaque_val = input_image->min_opaque_val;
+ double remapping_error=0;
+
+ if (!liq_image_get_row_f(input_image, 0)) { // trigger lazy conversion
+ return -1;
+ }
+
+ struct nearest_map *const n = nearest_init(map, fast);
+
+ const unsigned int max_threads = omp_get_max_threads();
+ viter_state average_color[(VITER_CACHE_LINE_GAP+map->colors) * max_threads];
+ viter_init(map, max_threads, average_color);
+
+ #pragma omp parallel for if (rows*cols > 3000) \
+ schedule(static) default(none) shared(average_color) reduction(+:remapping_error)
+ for(int row = 0; row < rows; ++row) {
+ const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row);
+ unsigned int last_match=0;
+ for(unsigned int col = 0; col < cols; ++col) {
+ f_pixel px = row_pixels[col];
+ float diff;
+
+ output_pixels[row][col] = last_match = nearest_search(n, px, last_match, min_opaque_val, &diff);
+
+ remapping_error += diff;
+ viter_update_color(px, 1.0, map, last_match, omp_get_thread_num(), average_color);
+ }
+ }
+
+ viter_finalize(map, max_threads, average_color);
+
+ nearest_free(n);
+
+ return remapping_error / (input_image->width * input_image->height);
+}
+
+inline static f_pixel get_dithered_pixel(const float dither_level, const float max_dither_error, const f_pixel thiserr, const f_pixel px)
+{
+ /* Use Floyd-Steinberg errors to adjust actual color. */
+ const float sr = thiserr.r * dither_level,
+ sg = thiserr.g * dither_level,
+ sb = thiserr.b * dither_level,
+ sa = thiserr.a * dither_level;
+
+ float ratio = 1.0;
+
+ // allowing some overflow prevents undithered bands caused by clamping of all channels
+ if (px.r + sr > 1.03) ratio = MIN(ratio, (1.03-px.r)/sr);
+ else if (px.r + sr < 0) ratio = MIN(ratio, px.r/-sr);
+ if (px.g + sg > 1.03) ratio = MIN(ratio, (1.03-px.g)/sg);
+ else if (px.g + sg < 0) ratio = MIN(ratio, px.g/-sg);
+ if (px.b + sb > 1.03) ratio = MIN(ratio, (1.03-px.b)/sb);
+ else if (px.b + sb < 0) ratio = MIN(ratio, px.b/-sb);
+
+ float a = px.a + sa;
+ if (a > 1.0) { a = 1.0; }
+ else if (a < 0) { a = 0; }
+
+ // If dithering error is crazy high, don't propagate it that much
+ // This prevents crazy geen pixels popping out of the blue (or red or black! ;)
+ const float dither_error = sr*sr + sg*sg + sb*sb + sa*sa;
+ if (dither_error > max_dither_error) {
+ ratio *= 0.8;
+ } else if (dither_error < 2.f/256.f/256.f) {
+ // don't dither areas that don't have noticeable error — makes file smaller
+ return px;
+ }
+
+ return (f_pixel){
+ .r=px.r + sr * ratio,
+ .g=px.g + sg * ratio,
+ .b=px.b + sb * ratio,
+ .a=a,
+ };
+}
+
+/**
+ Uses edge/noise map to apply dithering only to flat areas. Dithering on edges creates jagged lines, and noisy areas are "naturally" dithered.
+
+ If output_image_is_remapped is true, only pixels noticeably changed by error diffusion will be written to output image.
+ */
+static void remap_to_palette_floyd(liq_image *input_image, unsigned char *const output_pixels[], const colormap *map, const float max_dither_error, const bool use_dither_map, const bool output_image_is_remapped, float base_dithering_level)
+{
+ const unsigned int rows = input_image->height, cols = input_image->width;
+ const unsigned char *dither_map = use_dither_map ? (input_image->dither_map ? input_image->dither_map : input_image->edges) : NULL;
+ const float min_opaque_val = input_image->min_opaque_val;
+
+ const colormap_item *acolormap = map->palette;
+
+ struct nearest_map *const n = nearest_init(map, false);
+
+ /* Initialize Floyd-Steinberg error vectors. */
+ f_pixel *restrict thiserr, *restrict nexterr;
+ thiserr = input_image->malloc((cols + 2) * sizeof(*thiserr) * 2); // +2 saves from checking out of bounds access
+ nexterr = thiserr + (cols + 2);
+ srand(12345); /* deterministic dithering is better for comparing results */
+ if (!thiserr) return;
+
+ for (unsigned int col = 0; col < cols + 2; ++col) {
+ const double rand_max = RAND_MAX;
+ thiserr[col].r = ((double)rand() - rand_max/2.0)/rand_max/255.0;
+ thiserr[col].g = ((double)rand() - rand_max/2.0)/rand_max/255.0;
+ thiserr[col].b = ((double)rand() - rand_max/2.0)/rand_max/255.0;
+ thiserr[col].a = ((double)rand() - rand_max/2.0)/rand_max/255.0;
+ }
+
+ // response to this value is non-linear and without it any value < 0.8 would give almost no dithering
+ base_dithering_level = 1.0 - (1.0-base_dithering_level)*(1.0-base_dithering_level)*(1.0-base_dithering_level);
+
+ if (dither_map) {
+ base_dithering_level *= 1.0/255.0; // convert byte to float
+ }
+ base_dithering_level *= 15.0/16.0; // prevent small errors from accumulating
+
+ bool fs_direction = true;
+ unsigned int last_match=0;
+ for (unsigned int row = 0; row < rows; ++row) {
+ memset(nexterr, 0, (cols + 2) * sizeof(*nexterr));
+
+ unsigned int col = (fs_direction) ? 0 : (cols - 1);
+ const f_pixel *const row_pixels = liq_image_get_row_f(input_image, row);
+
+ do {
+ float dither_level = base_dithering_level;
+ if (dither_map) {
+ dither_level *= dither_map[row*cols + col];
+ }
+
+ const f_pixel spx = get_dithered_pixel(dither_level, max_dither_error, thiserr[col + 1], row_pixels[col]);
+
+ const unsigned int guessed_match = output_image_is_remapped ? output_pixels[row][col] : last_match;
+ output_pixels[row][col] = last_match = nearest_search(n, spx, guessed_match, min_opaque_val, NULL);
+
+ const f_pixel xp = acolormap[last_match].acolor;
+ f_pixel err = {
+ .r = (spx.r - xp.r),
+ .g = (spx.g - xp.g),
+ .b = (spx.b - xp.b),
+ .a = (spx.a - xp.a),
+ };
+
+ // If dithering error is crazy high, don't propagate it that much
+ // This prevents crazy geen pixels popping out of the blue (or red or black! ;)
+ if (err.r*err.r + err.g*err.g + err.b*err.b + err.a*err.a > max_dither_error) {
+ dither_level *= 0.75;
+ }
+
+ const float colorimp = (3.0f + acolormap[last_match].acolor.a)/4.0f * dither_level;
+ err.r *= colorimp;
+ err.g *= colorimp;
+ err.b *= colorimp;
+ err.a *= dither_level;
+
+ /* Propagate Floyd-Steinberg error terms. */
+ if (fs_direction) {
+ thiserr[col + 2].a += err.a * (7.f/16.f);
+ thiserr[col + 2].r += err.r * (7.f/16.f);
+ thiserr[col + 2].g += err.g * (7.f/16.f);
+ thiserr[col + 2].b += err.b * (7.f/16.f);
+
+ nexterr[col + 2].a = err.a * (1.f/16.f);
+ nexterr[col + 2].r = err.r * (1.f/16.f);
+ nexterr[col + 2].g = err.g * (1.f/16.f);
+ nexterr[col + 2].b = err.b * (1.f/16.f);
+
+ nexterr[col + 1].a += err.a * (5.f/16.f);
+ nexterr[col + 1].r += err.r * (5.f/16.f);
+ nexterr[col + 1].g += err.g * (5.f/16.f);
+ nexterr[col + 1].b += err.b * (5.f/16.f);
+
+ nexterr[col ].a += err.a * (3.f/16.f);
+ nexterr[col ].r += err.r * (3.f/16.f);
+ nexterr[col ].g += err.g * (3.f/16.f);
+ nexterr[col ].b += err.b * (3.f/16.f);
+
+ } else {
+ thiserr[col ].a += err.a * (7.f/16.f);
+ thiserr[col ].r += err.r * (7.f/16.f);
+ thiserr[col ].g += err.g * (7.f/16.f);
+ thiserr[col ].b += err.b * (7.f/16.f);
+
+ nexterr[col ].a = err.a * (1.f/16.f);
+ nexterr[col ].r = err.r * (1.f/16.f);
+ nexterr[col ].g = err.g * (1.f/16.f);
+ nexterr[col ].b = err.b * (1.f/16.f);
+
+ nexterr[col + 1].a += err.a * (5.f/16.f);
+ nexterr[col + 1].r += err.r * (5.f/16.f);
+ nexterr[col + 1].g += err.g * (5.f/16.f);
+ nexterr[col + 1].b += err.b * (5.f/16.f);
+
+ nexterr[col + 2].a += err.a * (3.f/16.f);
+ nexterr[col + 2].r += err.r * (3.f/16.f);
+ nexterr[col + 2].g += err.g * (3.f/16.f);
+ nexterr[col + 2].b += err.b * (3.f/16.f);
+ }
+
+ // remapping is done in zig-zag
+ if (fs_direction) {
+ ++col;
+ if (col >= cols) break;
+ } else {
+ if (col <= 0) break;
+ --col;
+ }
+ } while(1);
+
+ f_pixel *const temperr = thiserr;
+ thiserr = nexterr;
+ nexterr = temperr;
+ fs_direction = !fs_direction;
+ }
+
+ input_image->free(MIN(thiserr, nexterr)); // MIN because pointers were swapped
+ nearest_free(n);
+}
+
+
+/* histogram contains information how many times each color is present in the image, weighted by importance_map */
+static histogram *get_histogram(liq_image *input_image, const liq_attr *options)
+{
+ unsigned int ignorebits=MAX(options->min_posterization_output, options->min_posterization_input);
+ const unsigned int cols = input_image->width, rows = input_image->height;
+
+ if (!input_image->noise && options->use_contrast_maps) {
+ contrast_maps(input_image);
+ }
+
+ /*
+ ** Step 2: attempt to make a histogram of the colors, unclustered.
+ ** If at first we don't succeed, increase ignorebits to increase color
+ ** coherence and try again.
+ */
+
+ unsigned int maxcolors = options->max_histogram_entries;
+
+ struct acolorhash_table *acht;
+ const bool all_rows_at_once = liq_image_can_use_rows(input_image);
+ do {
+ acht = pam_allocacolorhash(maxcolors, rows*cols, ignorebits, options->malloc, options->free);
+ if (!acht) return NULL;
+
+ // histogram uses noise contrast map for importance. Color accuracy in noisy areas is not very important.
+ // noise map does not include edges to avoid ruining anti-aliasing
+ for(unsigned int row=0; row < rows; row++) {
+ bool added_ok;
+ if (all_rows_at_once) {
+ added_ok = pam_computeacolorhash(acht, (const rgba_pixel *const *)input_image->rows, cols, rows, input_image->noise);
+ if (added_ok) break;
+ } else {
+ const rgba_pixel* rows_p[1] = { liq_image_get_row_rgba(input_image, row) };
+ added_ok = pam_computeacolorhash(acht, rows_p, cols, 1, input_image->noise ? &input_image->noise[row * cols] : NULL);
+ }
+ if (!added_ok) {
+ ignorebits++;
+ liq_verbose_printf(options, " too many colors! Scaling colors to improve clustering... %d", ignorebits);
+ pam_freeacolorhash(acht);
+ acht = NULL;
+ break;
+ }
+ }
+ } while(!acht);
+
+ if (input_image->noise) {
+ input_image->free(input_image->noise);
+ input_image->noise = NULL;
+ }
+
+ if (input_image->free_pixels && input_image->f_pixels) {
+ liq_image_free_rgba_source(input_image); // bow can free the RGBA source if copy has been made in f_pixels
+ }
+
+ histogram *hist = pam_acolorhashtoacolorhist(acht, input_image->gamma, options->malloc, options->free);
+ pam_freeacolorhash(acht);
+
+ if (hist) {
+ liq_verbose_printf(options, " made histogram...%d colors found", hist->size);
+ }
+ return hist;
+}
+
+static void modify_alpha(liq_image *input_image, rgba_pixel *const row_pixels)
+{
+ /* IE6 makes colors with even slightest transparency completely transparent,
+ thus to improve situation in IE, make colors that are less than ~10% transparent
+ completely opaque */
+
+ const float min_opaque_val = input_image->min_opaque_val;
+ const float almost_opaque_val = min_opaque_val * 169.f/256.f;
+ const unsigned int almost_opaque_val_int = (min_opaque_val * 169.f/256.f)*255.f;
+
+ for(unsigned int col = 0; col < input_image->width; col++) {
+ const rgba_pixel px = row_pixels[col];
+
+ /* ie bug: to avoid visible step caused by forced opaqueness, linearily raise opaqueness of almost-opaque colors */
+ if (px.a >= almost_opaque_val_int) {
+ float al = px.a / 255.f;
+ al = almost_opaque_val + (al-almost_opaque_val) * (1.f-almost_opaque_val) / (min_opaque_val-almost_opaque_val);
+ al *= 256.f;
+ row_pixels[col].a = al >= 255.f ? 255 : al;
+ }
+ }
+}
+
+/**
+ Builds two maps:
+ noise - approximation of areas with high-frequency noise, except straight edges. 1=flat, 0=noisy.
+ edges - noise map including all edges
+ */
+static void contrast_maps(liq_image *image)
+{
+ const int cols = image->width, rows = image->height;
+ if (cols < 4 || rows < 4 || (3*cols*rows) > LIQ_HIGH_MEMORY_LIMIT) {
+ return;
+ }
+
+ unsigned char *restrict noise = image->malloc(cols*rows);
+ unsigned char *restrict edges = image->malloc(cols*rows);
+ unsigned char *restrict tmp = image->malloc(cols*rows);
+
+ if (!noise || !edges || !tmp) {
+ return;
+ }
+
+ const f_pixel *curr_row, *prev_row, *next_row;
+ curr_row = prev_row = next_row = liq_image_get_row_f(image, 0);
+
+ for (int j=0; j < rows; j++) {
+ prev_row = curr_row;
+ curr_row = next_row;
+ next_row = liq_image_get_row_f(image, MIN(rows-1,j+1));
+
+ f_pixel prev, curr = curr_row[0], next=curr;
+ for (int i=0; i < cols; i++) {
+ prev=curr;
+ curr=next;
+ next = curr_row[MIN(cols-1,i+1)];
+
+ // contrast is difference between pixels neighbouring horizontally and vertically
+ const float a = fabsf(prev.a+next.a - curr.a*2.f),
+ r = fabsf(prev.r+next.r - curr.r*2.f),
+ g = fabsf(prev.g+next.g - curr.g*2.f),
+ b = fabsf(prev.b+next.b - curr.b*2.f);
+
+ const f_pixel prevl = prev_row[i];
+ const f_pixel nextl = next_row[i];
+
+ const float a1 = fabsf(prevl.a+nextl.a - curr.a*2.f),
+ r1 = fabsf(prevl.r+nextl.r - curr.r*2.f),
+ g1 = fabsf(prevl.g+nextl.g - curr.g*2.f),
+ b1 = fabsf(prevl.b+nextl.b - curr.b*2.f);
+
+ const float horiz = MAX(MAX(a,r),MAX(g,b));
+ const float vert = MAX(MAX(a1,r1),MAX(g1,b1));
+ const float edge = MAX(horiz,vert);
+ float z = edge - fabsf(horiz-vert)*.5f;
+ z = 1.f - MAX(z,MIN(horiz,vert));
+ z *= z; // noise is amplified
+ z *= z;
+
+ z *= 256.f;
+ noise[j*cols+i] = z < 256 ? z : 255;
+ z = (1.f-edge)*256.f;
+ edges[j*cols+i] = z < 256 ? z : 255;
+ }
+ }
+
+ // noise areas are shrunk and then expanded to remove thin edges from the map
+ liq_max3(noise, tmp, cols, rows);
+ liq_max3(tmp, noise, cols, rows);
+
+ liq_blur(noise, tmp, noise, cols, rows, 3);
+
+ liq_max3(noise, tmp, cols, rows);
+
+ liq_min3(tmp, noise, cols, rows);
+ liq_min3(noise, tmp, cols, rows);
+ liq_min3(tmp, noise, cols, rows);
+
+ liq_min3(edges, tmp, cols, rows);
+ liq_max3(tmp, edges, cols, rows);
+ for(int i=0; i < cols*rows; i++) edges[i] = MIN(noise[i], edges[i]);
+
+ image->free(tmp);
+
+ image->noise = noise;
+ image->edges = edges;
+}
+
+/**
+ * Builds map of neighbor pixels mapped to the same palette entry
+ *
+ * For efficiency/simplicity it mainly looks for same consecutive pixels horizontally
+ * and peeks 1 pixel above/below. Full 2d algorithm doesn't improve it significantly.
+ * Correct flood fill doesn't have visually good properties.
+ */
+static void update_dither_map(unsigned char *const *const row_pointers, liq_image *input_image)
+{
+ const unsigned int width = input_image->width;
+ const unsigned int height = input_image->height;
+ unsigned char *const edges = input_image->edges;
+
+ for(unsigned int row=0; row < height; row++) {
+ unsigned char lastpixel = row_pointers[row][0];
+ unsigned int lastcol=0;
+
+ for(unsigned int col=1; col < width; col++) {
+ const unsigned char px = row_pointers[row][col];
+
+ if (px != lastpixel || col == width-1) {
+ float neighbor_count = 2.5f + col-lastcol;
+
+ unsigned int i=lastcol;
+ while(i < col) {
+ if (row > 0) {
+ unsigned char pixelabove = row_pointers[row-1][i];
+ if (pixelabove == lastpixel) neighbor_count += 1.f;
+ }
+ if (row < height-1) {
+ unsigned char pixelbelow = row_pointers[row+1][i];
+ if (pixelbelow == lastpixel) neighbor_count += 1.f;
+ }
+ i++;
+ }
+
+ while(lastcol <= col) {
+ float e = edges[row*width + lastcol] / 255.f;
+ e *= 1.f - 2.5f/neighbor_count;
+ edges[row*width + lastcol++] = e * 255.f;
+ }
+ lastpixel = px;
+ }
+ }
+ }
+ input_image->dither_map = input_image->edges;
+ input_image->edges = NULL;
+}
+
+static void adjust_histogram_callback(hist_item *item, float diff)
+{
+ item->adjusted_weight = (item->perceptual_weight+item->adjusted_weight) * (sqrtf(1.f+diff));
+}
+
+/**
+ Repeats mediancut with different histogram weights to find palette with minimum error.
+
+ feedback_loop_trials controls how long the search will take. < 0 skips the iteration.
+ */
+static colormap *find_best_palette(histogram *hist, const liq_attr *options, const double max_mse, double *palette_error_p)
+{
+ unsigned int max_colors = options->max_colors;
+ // if output is posterized it doesn't make sense to aim for perfrect colors, so increase target_mse
+ // at this point actual gamma is not set, so very conservative posterization estimate is used
+ const double target_mse = MIN(max_mse, MAX(options->target_mse, pow((1<<options->min_posterization_output)/1024.0, 2)));
+ int feedback_loop_trials = options->feedback_loop_trials;
+ colormap *acolormap = NULL;
+ double least_error = MAX_DIFF;
+ double target_mse_overshoot = feedback_loop_trials>0 ? 1.05 : 1.0;
+ const double percent = (double)(feedback_loop_trials>0?feedback_loop_trials:1)/100.0;
+
+ do {
+ colormap *newmap = mediancut(hist, options->min_opaque_val, max_colors,
+ target_mse * target_mse_overshoot, MAX(MAX(90.0/65536.0, target_mse), least_error)*1.2,
+ options->malloc, options->free);
+ if (!newmap) {
+ return NULL;
+ }
+
+ if (feedback_loop_trials <= 0) {
+ return newmap;
+ }
+
+ // after palette has been created, total error (MSE) is calculated to keep the best palette
+ // at the same time Voronoi iteration is done to improve the palette
+ // and histogram weights are adjusted based on remapping error to give more weight to poorly matched colors
+
+ const bool first_run_of_target_mse = !acolormap && target_mse > 0;
+ double total_error = viter_do_iteration(hist, newmap, options->min_opaque_val, first_run_of_target_mse ? NULL : adjust_histogram_callback, !acolormap || options->fast_palette);
+
+ // goal is to increase quality or to reduce number of colors used if quality is good enough
+ if (!acolormap || total_error < least_error || (total_error <= target_mse && newmap->colors < max_colors)) {
+ if (acolormap) pam_freecolormap(acolormap);
+ acolormap = newmap;
+
+ if (total_error < target_mse && total_error > 0) {
+ // voronoi iteration improves quality above what mediancut aims for
+ // this compensates for it, making mediancut aim for worse
+ target_mse_overshoot = MIN(target_mse_overshoot*1.25, target_mse/total_error);
+ }
+
+ least_error = total_error;
+
+ // if number of colors could be reduced, try to keep it that way
+ // but allow extra color as a bit of wiggle room in case quality can be improved too
+ max_colors = MIN(newmap->colors+1, max_colors);
+
+ feedback_loop_trials -= 1; // asymptotic improvement could make it go on forever
+ } else {
+ for(unsigned int j=0; j < hist->size; j++) {
+ hist->achv[j].adjusted_weight = (hist->achv[j].perceptual_weight + hist->achv[j].adjusted_weight)/2.0;
+ }
+
+ target_mse_overshoot = 1.0;
+ feedback_loop_trials -= 6;
+ // if error is really bad, it's unlikely to improve, so end sooner
+ if (total_error > least_error*4) feedback_loop_trials -= 3;
+ pam_freecolormap(newmap);
+ }
+
+ liq_verbose_printf(options, " selecting colors...%d%%",100-MAX(0,(int)(feedback_loop_trials/percent)));
+ }
+ while(feedback_loop_trials > 0);
+
+ // likely_colormap_index (used and set in viter_do_iteration) can't point to index outside colormap
+ if (acolormap->colors < 256) {
+ for(unsigned int j=0; j < hist->size; j++) {
+ if (hist->achv[j].tmp.likely_colormap_index >= acolormap->colors) {
+ hist->achv[j].tmp.likely_colormap_index = 0; // actual value doesn't matter, as the guess is out of date anyway
+ }
+ }
+ }
+ *palette_error_p = least_error;
+ return acolormap;
+}
+
+static liq_result *pngquant_quantize(histogram *hist, const liq_attr *options, const double gamma)
+{
+ colormap *acolormap;
+ double palette_error = -1;
+
+ // no point having perfect match with imperfect colors (ignorebits > 0)
+ const bool fast_palette = options->fast_palette || hist->ignorebits > 0;
+ const bool few_input_colors = hist->size <= options->max_colors;
+
+ // If image has few colors to begin with (and no quality degradation is required)
+ // then it's possible to skip quantization entirely
+ if (few_input_colors && options->target_mse == 0) {
+ acolormap = pam_colormap(hist->size, options->malloc, options->free);
+ for(unsigned int i=0; i < hist->size; i++) {
+ acolormap->palette[i].acolor = hist->achv[i].acolor;
+ acolormap->palette[i].popularity = hist->achv[i].perceptual_weight;
+ }
+ palette_error = 0;
+ } else {
+ const double max_mse = options->max_mse * (few_input_colors ? 0.33 : 1.0); // when degrading image that's already paletted, require much higher improvement, since pal2pal often looks bad and there's little gain
+ acolormap = find_best_palette(hist, options, max_mse, &palette_error);
+ if (!acolormap) {
+ return NULL;
+ }
+
+ // Voronoi iteration approaches local minimum for the palette
+ const double iteration_limit = options->voronoi_iteration_limit;
+ unsigned int iterations = options->voronoi_iterations;
+
+ if (!iterations && palette_error < 0 && max_mse < MAX_DIFF) iterations = 1; // otherwise total error is never calculated and MSE limit won't work
+
+ if (iterations) {
+ verbose_print(options, " moving colormap towards local minimum");
+
+ double previous_palette_error = MAX_DIFF;
+
+ for(unsigned int i=0; i < iterations; i++) {
+ palette_error = viter_do_iteration(hist, acolormap, options->min_opaque_val, NULL, i==0 || options->fast_palette);
+
+ if (fabs(previous_palette_error-palette_error) < iteration_limit) {
+ break;
+ }
+
+ if (palette_error > max_mse*1.5) { // probably hopeless
+ if (palette_error > max_mse*3.0) break; // definitely hopeless
+ i++;
+ }
+
+ previous_palette_error = palette_error;
+ }
+ }
+
+ if (palette_error > max_mse) {
+ liq_verbose_printf(options, " image degradation MSE=%.3f (Q=%d) exceeded limit of %.3f (%d)",
+ palette_error*65536.0/6.0, mse_to_quality(palette_error),
+ max_mse*65536.0/6.0, mse_to_quality(max_mse));
+ pam_freecolormap(acolormap);
+ return NULL;
+ }
+ }
+
+ sort_palette(acolormap, options);
+
+ liq_result *result = options->malloc(sizeof(liq_result));
+ if (!result) return NULL;
+ *result = (liq_result){
+ .magic_header = liq_result_magic,
+ .malloc = options->malloc,
+ .free = options->free,
+ .palette = acolormap,
+ .palette_error = palette_error,
+ .fast_palette = fast_palette,
+ .use_dither_map = options->use_dither_map,
+ .gamma = gamma,
+ .min_posterization_output = options->min_posterization_output,
+ };
+ return result;
+}
+
+LIQ_EXPORT liq_error liq_write_remapped_image(liq_result *result, liq_image *input_image, void *buffer, size_t buffer_size)
+{
+ if (!CHECK_STRUCT_TYPE(result, liq_result)) {
+ return LIQ_INVALID_POINTER;
+ }
+ if (!CHECK_STRUCT_TYPE(input_image, liq_image)) {
+ return LIQ_INVALID_POINTER;
+ }
+ if (!CHECK_USER_POINTER(buffer)) {
+ return LIQ_INVALID_POINTER;
+ }
+
+ const size_t required_size = input_image->width * input_image->height;
+ if (buffer_size < required_size) {
+ return LIQ_BUFFER_TOO_SMALL;
+ }
+
+ unsigned char *rows[input_image->height];
+ unsigned char *buffer_bytes = buffer;
+ for(unsigned int i=0; i < input_image->height; i++) {
+ rows[i] = &buffer_bytes[input_image->width * i];
+ }
+ return liq_write_remapped_image_rows(result, input_image, rows);
+}
+
+LIQ_EXPORT liq_error liq_write_remapped_image_rows(liq_result *quant, liq_image *input_image, unsigned char **row_pointers)
+{
+ if (!CHECK_STRUCT_TYPE(quant, liq_result)) return LIQ_INVALID_POINTER;
+ if (!CHECK_STRUCT_TYPE(input_image, liq_image)) return LIQ_INVALID_POINTER;
+ for(unsigned int i=0; i < input_image->height; i++) {
+ if (!CHECK_USER_POINTER(row_pointers+i) || !CHECK_USER_POINTER(row_pointers[i])) return LIQ_INVALID_POINTER;
+ }
+
+ if (quant->remapping) {
+ liq_remapping_result_destroy(quant->remapping);
+ }
+ liq_remapping_result *const result = quant->remapping = liq_remapping_result_create(quant);
+ if (!result) return LIQ_OUT_OF_MEMORY;
+
+ if (!input_image->edges && !input_image->dither_map && quant->use_dither_map) {
+ contrast_maps(input_image);
+ }
+
+ /*
+ ** Step 4: map the colors in the image to their closest match in the
+ ** new colormap, and write 'em out.
+ */
+
+ float remapping_error = result->palette_error;
+ if (result->dither_level == 0) {
+ set_rounded_palette(&result->int_palette, result->palette, result->gamma, quant->min_posterization_output);
+ remapping_error = remap_to_palette(input_image, row_pointers, result->palette, quant->fast_palette);
+ } else {
+ const bool generate_dither_map = result->use_dither_map && (input_image->edges && !input_image->dither_map);
+ if (generate_dither_map) {
+ // If dithering (with dither map) is required, this image is used to find areas that require dithering
+ remapping_error = remap_to_palette(input_image, row_pointers, result->palette, quant->fast_palette);
+ update_dither_map(row_pointers, input_image);
+ }
+
+ // remapping above was the last chance to do voronoi iteration, hence the final palette is set after remapping
+ set_rounded_palette(&result->int_palette, result->palette, result->gamma, quant->min_posterization_output);
+
+ remap_to_palette_floyd(input_image, row_pointers, result->palette,
+ MAX(remapping_error*2.4, 16.f/256.f), result->use_dither_map, generate_dither_map, result->dither_level);
+ }
+
+ // remapping error from dithered image is absurd, so always non-dithered value is used
+ // palette_error includes some perceptual weighting from histogram which is closer correlated with dssim
+ // so that should be used when possible.
+ if (result->palette_error < 0) {
+ result->palette_error = remapping_error;
+ }
+
+ return LIQ_OK;
+}
+
+LIQ_EXPORT int liq_version() {
+ return LIQ_VERSION;
+}
diff --git a/src/drivers/libimagequant/libimagequant.h b/src/drivers/libimagequant/libimagequant.h
new file mode 100644
index 0000000..2b66084
--- /dev/null
+++ b/src/drivers/libimagequant/libimagequant.h
@@ -0,0 +1,109 @@
+/*
+ * http://pngquant.org
+ */
+
+#ifndef LIBIMAGEQUANT_H
+#define LIBIMAGEQUANT_H
+
+#ifndef LIQ_EXPORT
+#define LIQ_EXPORT extern
+#endif
+
+#define LIQ_VERSION 20305
+#define LIQ_VERSION_STRING "2.3.5"
+
+#ifndef LIQ_PRIVATE
+#if defined(__GNUC__) || defined (__llvm__)
+#define LIQ_PRIVATE __attribute__((visibility("hidden")))
+#else
+#define LIQ_PRIVATE
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+typedef struct liq_attr liq_attr;
+typedef struct liq_image liq_image;
+typedef struct liq_result liq_result;
+
+typedef struct liq_color {
+ unsigned char r, g, b, a;
+} liq_color;
+
+typedef struct liq_palette {
+ unsigned int count;
+ liq_color entries[256];
+} liq_palette;
+
+typedef enum liq_error {
+ LIQ_OK = 0,
+ LIQ_QUALITY_TOO_LOW = 99,
+ LIQ_VALUE_OUT_OF_RANGE = 100,
+ LIQ_OUT_OF_MEMORY,
+ LIQ_NOT_READY,
+ LIQ_BITMAP_NOT_AVAILABLE,
+ LIQ_BUFFER_TOO_SMALL,
+ LIQ_INVALID_POINTER,
+} liq_error;
+
+enum liq_ownership {LIQ_OWN_ROWS=4, LIQ_OWN_PIXELS=8};
+
+LIQ_EXPORT liq_attr* liq_attr_create(void);
+LIQ_EXPORT liq_attr* liq_attr_create_with_allocator(void* (*malloc)(size_t), void (*free)(void*));
+LIQ_EXPORT liq_attr* liq_attr_copy(liq_attr* orig);
+LIQ_EXPORT void liq_attr_destroy(liq_attr* attr);
+
+LIQ_EXPORT liq_error liq_set_max_colors(liq_attr* attr, int colors);
+LIQ_EXPORT int liq_get_max_colors(const liq_attr* attr);
+LIQ_EXPORT liq_error liq_set_speed(liq_attr* attr, int speed);
+LIQ_EXPORT int liq_get_speed(const liq_attr* attr);
+LIQ_EXPORT liq_error liq_set_min_opacity(liq_attr* attr, int min);
+LIQ_EXPORT int liq_get_min_opacity(const liq_attr* attr);
+LIQ_EXPORT liq_error liq_set_min_posterization(liq_attr* attr, int bits);
+LIQ_EXPORT int liq_get_min_posterization(const liq_attr* attr);
+LIQ_EXPORT liq_error liq_set_quality(liq_attr* attr, int minimum, int maximum);
+LIQ_EXPORT int liq_get_min_quality(const liq_attr* attr);
+LIQ_EXPORT int liq_get_max_quality(const liq_attr* attr);
+LIQ_EXPORT void liq_set_last_index_transparent(liq_attr* attr, int is_last);
+
+typedef void liq_log_callback_function(const liq_attr*, const char* message, void* user_info);
+typedef void liq_log_flush_callback_function(const liq_attr*, void* user_info);
+LIQ_EXPORT void liq_set_log_callback(liq_attr*, liq_log_callback_function*, void* user_info);
+LIQ_EXPORT void liq_set_log_flush_callback(liq_attr*, liq_log_flush_callback_function*, void* user_info);
+
+LIQ_EXPORT liq_image* liq_image_create_rgba_rows(liq_attr* attr, void* rows[], int width, int height, double gamma);
+LIQ_EXPORT liq_image* liq_image_create_rgba(liq_attr* attr, void* bitmap, int width, int height, double gamma);
+
+typedef void liq_image_get_rgba_row_callback(liq_color row_out[], int row, int width, void* user_info);
+LIQ_EXPORT liq_image* liq_image_create_custom(liq_attr* attr, liq_image_get_rgba_row_callback* row_callback, void* user_info, int width, int height, double gamma);
+
+LIQ_EXPORT liq_error liq_image_set_memory_ownership(liq_image* image, int ownership_flags);
+LIQ_EXPORT int liq_image_get_width(const liq_image* img);
+LIQ_EXPORT int liq_image_get_height(const liq_image* img);
+LIQ_EXPORT void liq_image_destroy(liq_image* img);
+
+LIQ_EXPORT liq_result* liq_quantize_image(liq_attr* options, liq_image* input_image);
+
+LIQ_EXPORT liq_error liq_set_dithering_level(liq_result* res, float dither_level);
+LIQ_EXPORT liq_error liq_set_output_gamma(liq_result* res, double gamma);
+LIQ_EXPORT double liq_get_output_gamma(const liq_result* result);
+
+LIQ_EXPORT const liq_palette* liq_get_palette(liq_result* result);
+
+LIQ_EXPORT liq_error liq_write_remapped_image(liq_result* result, liq_image* input_image, void* buffer, size_t buffer_size);
+LIQ_EXPORT liq_error liq_write_remapped_image_rows(liq_result* result, liq_image* input_image, unsigned char** row_pointers);
+
+LIQ_EXPORT double liq_get_quantization_error(liq_result* result);
+LIQ_EXPORT int liq_get_quantization_quality(liq_result* result);
+
+LIQ_EXPORT void liq_result_destroy(liq_result*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/drivers/libimagequant/mediancut.c b/src/drivers/libimagequant/mediancut.c
new file mode 100644
index 0000000..b376c52
--- /dev/null
+++ b/src/drivers/libimagequant/mediancut.c
@@ -0,0 +1,507 @@
+/*
+** Copyright (C) 1989, 1991 by Jef Poskanzer.
+** Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by
+** Stefan Schneider.
+** © 2009-2013 by Kornel Lesinski.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "libimagequant.h"
+#include "pam.h"
+#include "mediancut.h"
+
+#define index_of_channel(ch) (offsetof(f_pixel,ch)/sizeof(float))
+
+static f_pixel averagepixels(unsigned int clrs, const hist_item achv[], float min_opaque_val, const f_pixel center);
+
+struct box {
+ f_pixel color;
+ f_pixel variance;
+ double sum, total_error, max_error;
+ unsigned int ind;
+ unsigned int colors;
+};
+
+ALWAYS_INLINE static double variance_diff(double val, const double good_enough);
+inline static double variance_diff(double val, const double good_enough)
+{
+ val *= val;
+ if (val < good_enough*good_enough) return val*0.25;
+ return val;
+}
+
+/** Weighted per-channel variance of the box. It's used to decide which channel to split by */
+static f_pixel box_variance(const hist_item achv[], const struct box *box)
+{
+ f_pixel mean = box->color;
+ double variancea=0, variancer=0, varianceg=0, varianceb=0;
+
+ for(unsigned int i = 0; i < box->colors; ++i) {
+ f_pixel px = achv[box->ind + i].acolor;
+ double weight = achv[box->ind + i].adjusted_weight;
+ variancea += variance_diff(mean.a - px.a, 2.0/256.0)*weight;
+ variancer += variance_diff(mean.r - px.r, 1.0/256.0)*weight;
+ varianceg += variance_diff(mean.g - px.g, 1.0/256.0)*weight;
+ varianceb += variance_diff(mean.b - px.b, 1.0/256.0)*weight;
+ }
+
+ return (f_pixel){
+ .a = variancea*(4.0/16.0),
+ .r = variancer*(7.0/16.0),
+ .g = varianceg*(9.0/16.0),
+ .b = varianceb*(5.0/16.0),
+ };
+}
+
+static double box_max_error(const hist_item achv[], const struct box *box)
+{
+ f_pixel mean = box->color;
+ double max_error = 0;
+
+ for(unsigned int i = 0; i < box->colors; ++i) {
+ const double diff = colordifference(mean, achv[box->ind + i].acolor);
+ if (diff > max_error) {
+ max_error = diff;
+ }
+ }
+ return max_error;
+}
+
+ALWAYS_INLINE static double color_weight(f_pixel median, hist_item h);
+
+static inline void hist_item_swap(hist_item *l, hist_item *r)
+{
+ if (l != r) {
+ hist_item t = *l;
+ *l = *r;
+ *r = t;
+ }
+}
+
+ALWAYS_INLINE static unsigned int qsort_pivot(const hist_item *const base, const unsigned int len);
+inline static unsigned int qsort_pivot(const hist_item *const base, const unsigned int len)
+{
+ if (len < 32) {
+ return len/2;
+ }
+
+ const unsigned int aidx=8, bidx=len/2, cidx=len-1;
+ const unsigned int a=base[aidx].tmp.sort_value, b=base[bidx].tmp.sort_value, c=base[cidx].tmp.sort_value;
+ return (a < b) ? ((b < c) ? bidx : ((a < c) ? cidx : aidx ))
+ : ((b > c) ? bidx : ((a < c) ? aidx : cidx ));
+}
+
+ALWAYS_INLINE static unsigned int qsort_partition(hist_item *const base, const unsigned int len);
+inline static unsigned int qsort_partition(hist_item *const base, const unsigned int len)
+{
+ unsigned int l = 1, r = len;
+ if (len >= 8) {
+ hist_item_swap(&base[0], &base[qsort_pivot(base,len)]);
+ }
+
+ const unsigned int pivot_value = base[0].tmp.sort_value;
+ while (l < r) {
+ if (base[l].tmp.sort_value >= pivot_value) {
+ l++;
+ } else {
+ while(l < --r && base[r].tmp.sort_value <= pivot_value) {}
+ hist_item_swap(&base[l], &base[r]);
+ }
+ }
+ l--;
+ hist_item_swap(&base[0], &base[l]);
+
+ return l;
+}
+
+/** quick select algorithm */
+static void hist_item_sort_range(hist_item *base, unsigned int len, unsigned int sort_start)
+{
+ for(;;) {
+ const unsigned int l = qsort_partition(base, len), r = l+1;
+
+ if (l > 0 && sort_start < l) {
+ len = l;
+ }
+ else if (r < len && sort_start > r) {
+ base += r; len -= r; sort_start -= r;
+ }
+ else break;
+ }
+}
+
+/** sorts array to make sum of weights lower than halfvar one side, returns edge between <halfvar and >halfvar parts of the set */
+static hist_item *hist_item_sort_halfvar(hist_item *base, unsigned int len, double *const lowervar, const double halfvar)
+{
+ do {
+ const unsigned int l = qsort_partition(base, len), r = l+1;
+
+ // check if sum of left side is smaller than half,
+ // if it is, then it doesn't need to be sorted
+ unsigned int t = 0; double tmpsum = *lowervar;
+ while (t <= l && tmpsum < halfvar) tmpsum += base[t++].color_weight;
+
+ if (tmpsum < halfvar) {
+ *lowervar = tmpsum;
+ } else {
+ if (l > 0) {
+ hist_item *res = hist_item_sort_halfvar(base, l, lowervar, halfvar);
+ if (res) return res;
+ } else {
+ // End of left recursion. This will be executed in order from the first element.
+ *lowervar += base[0].color_weight;
+ if (*lowervar > halfvar) return &base[0];
+ }
+ }
+
+ if (len > r) {
+ base += r; len -= r; // tail-recursive "call"
+ } else {
+ *lowervar += base[r].color_weight;
+ return (*lowervar > halfvar) ? &base[r] : NULL;
+ }
+ } while(1);
+}
+
+static f_pixel get_median(const struct box *b, hist_item achv[]);
+
+typedef struct {
+ unsigned int chan; float variance;
+} channelvariance;
+
+static int comparevariance(const void *ch1, const void *ch2)
+{
+ return ((const channelvariance*)ch1)->variance > ((const channelvariance*)ch2)->variance ? -1 :
+ (((const channelvariance*)ch1)->variance < ((const channelvariance*)ch2)->variance ? 1 : 0);
+}
+
+/** Finds which channels need to be sorted first and preproceses achv for fast sort */
+static double prepare_sort(struct box *b, hist_item achv[])
+{
+ /*
+ ** Sort dimensions by their variance, and then sort colors first by dimension with highest variance
+ */
+ channelvariance channels[4] = {
+ {index_of_channel(r), b->variance.r},
+ {index_of_channel(g), b->variance.g},
+ {index_of_channel(b), b->variance.b},
+ {index_of_channel(a), b->variance.a},
+ };
+
+ qsort(channels, 4, sizeof(channels[0]), comparevariance);
+
+ for(unsigned int i=0; i < b->colors; i++) {
+ const float *chans = (const float *)&achv[b->ind + i].acolor;
+ // Only the first channel really matters. When trying median cut many times
+ // with different histogram weights, I don't want sort randomness to influence outcome.
+ achv[b->ind + i].tmp.sort_value = ((unsigned int)(chans[channels[0].chan]*65535.0)<<16) |
+ (unsigned int)((chans[channels[2].chan] + chans[channels[1].chan]/2.0 + chans[channels[3].chan]/4.0)*65535.0);
+ }
+
+ const f_pixel median = get_median(b, achv);
+
+ // box will be split to make color_weight of each side even
+ const unsigned int ind = b->ind, end = ind+b->colors;
+ double totalvar = 0;
+ for(unsigned int j=ind; j < end; j++) totalvar += (achv[j].color_weight = color_weight(median, achv[j]));
+ return totalvar / 2.0;
+}
+
+/** finds median in unsorted set by sorting only minimum required */
+static f_pixel get_median(const struct box *b, hist_item achv[])
+{
+ const unsigned int median_start = (b->colors-1)/2;
+
+ hist_item_sort_range(&(achv[b->ind]), b->colors,
+ median_start);
+
+ if (b->colors&1) return achv[b->ind + median_start].acolor;
+
+ // technically the second color is not guaranteed to be sorted correctly
+ // but most of the time it is good enough to be useful
+ return averagepixels(2, &achv[b->ind + median_start], 1.0, (f_pixel){0.5,0.5,0.5,0.5});
+}
+
+/*
+ ** Find the best splittable box. -1 if no boxes are splittable.
+ */
+static int best_splittable_box(struct box* bv, unsigned int boxes, const double max_mse)
+{
+ int bi=-1; double maxsum=0;
+ for(unsigned int i=0; i < boxes; i++) {
+ if (bv[i].colors < 2) {
+ continue;
+ }
+
+ // looks only at max variance, because it's only going to split by it
+ const double cv = MAX(bv[i].variance.r, MAX(bv[i].variance.g,bv[i].variance.b));
+ double thissum = bv[i].sum * MAX(bv[i].variance.a, cv);
+
+ if (bv[i].max_error > max_mse) {
+ thissum = thissum* bv[i].max_error/max_mse;
+ }
+
+ if (thissum > maxsum) {
+ maxsum = thissum;
+ bi = i;
+ }
+ }
+ return bi;
+}
+
+inline static double color_weight(f_pixel median, hist_item h)
+{
+ float diff = colordifference(median, h.acolor);
+ // if color is "good enough", don't split further
+ if (diff < 2.f/256.f/256.f) diff /= 2.f;
+ return sqrt(diff) * (sqrt(1.0+h.adjusted_weight)-1.0);
+}
+
+static void set_colormap_from_boxes(colormap *map, struct box* bv, unsigned int boxes, hist_item *achv);
+static void adjust_histogram(hist_item *achv, const colormap *map, const struct box* bv, unsigned int boxes);
+
+double box_error(const struct box *box, const hist_item achv[])
+{
+ f_pixel avg = box->color;
+
+ double total_error=0;
+ for (unsigned int i = 0; i < box->colors; ++i) {
+ total_error += colordifference(avg, achv[box->ind + i].acolor) * achv[box->ind + i].perceptual_weight;
+ }
+
+ return total_error;
+}
+
+
+static bool total_box_error_below_target(double target_mse, struct box bv[], unsigned int boxes, const histogram *hist)
+{
+ target_mse *= hist->total_perceptual_weight;
+ double total_error=0;
+
+ for(unsigned int i=0; i < boxes; i++) {
+ // error is (re)calculated lazily
+ if (bv[i].total_error >= 0) {
+ total_error += bv[i].total_error;
+ }
+ if (total_error > target_mse) return false;
+ }
+
+ for(unsigned int i=0; i < boxes; i++) {
+ if (bv[i].total_error < 0) {
+ bv[i].total_error = box_error(&bv[i], hist->achv);
+ total_error += bv[i].total_error;
+ }
+ if (total_error > target_mse) return false;
+ }
+
+ return true;
+}
+
+/*
+ ** Here is the fun part, the median-cut colormap generator. This is based
+ ** on Paul Heckbert's paper, "Color Image Quantization for Frame Buffer
+ ** Display," SIGGRAPH 1982 Proceedings, page 297.
+ */
+LIQ_PRIVATE colormap *mediancut(histogram *hist, const float min_opaque_val, unsigned int newcolors, const double target_mse, const double max_mse, void* (*malloc)(size_t), void (*free)(void*))
+{
+ hist_item *achv = hist->achv;
+ struct box bv[newcolors];
+
+ /*
+ ** Set up the initial box.
+ */
+ bv[0].ind = 0;
+ bv[0].colors = hist->size;
+ bv[0].color = averagepixels(bv[0].colors, &achv[bv[0].ind], min_opaque_val, (f_pixel){0.5,0.5,0.5,0.5});
+ bv[0].variance = box_variance(achv, &bv[0]);
+ bv[0].max_error = box_max_error(achv, &bv[0]);
+ bv[0].sum = 0;
+ bv[0].total_error = -1;
+ for(unsigned int i=0; i < bv[0].colors; i++) bv[0].sum += achv[i].adjusted_weight;
+
+ unsigned int boxes = 1;
+
+ // remember smaller palette for fast searching
+ colormap *representative_subset = NULL;
+ unsigned int subset_size = ceilf(powf(newcolors,0.7f));
+
+ /*
+ ** Main loop: split boxes until we have enough.
+ */
+ while (boxes < newcolors) {
+
+ if (boxes == subset_size) {
+ representative_subset = pam_colormap(boxes, malloc, free);
+ set_colormap_from_boxes(representative_subset, bv, boxes, achv);
+ }
+
+ // first splits boxes that exceed quality limit (to have colors for things like odd green pixel),
+ // later raises the limit to allow large smooth areas/gradients get colors.
+ const double current_max_mse = max_mse + (boxes/(double)newcolors)*16.0*max_mse;
+ const int bi = best_splittable_box(bv, boxes, current_max_mse);
+ if (bi < 0)
+ break; /* ran out of colors! */
+
+ unsigned int indx = bv[bi].ind;
+ unsigned int clrs = bv[bi].colors;
+
+ /*
+ Classic implementation tries to get even number of colors or pixels in each subdivision.
+
+ Here, instead of popularity I use (sqrt(popularity)*variance) metric.
+ Each subdivision balances number of pixels (popular colors) and low variance -
+ boxes can be large if they have similar colors. Later boxes with high variance
+ will be more likely to be split.
+
+ Median used as expected value gives much better results than mean.
+ */
+
+ const double halfvar = prepare_sort(&bv[bi], achv);
+ double lowervar=0;
+
+ // hist_item_sort_halfvar sorts and sums lowervar at the same time
+ // returns item to break at …minus one, which does smell like an off-by-one error.
+ hist_item *break_p = hist_item_sort_halfvar(&achv[indx], clrs, &lowervar, halfvar);
+ unsigned int break_at = MIN(clrs-1, break_p - &achv[indx] + 1);
+
+ /*
+ ** Split the box.
+ */
+ double sm = bv[bi].sum;
+ double lowersum = 0;
+ for(unsigned int i=0; i < break_at; i++) lowersum += achv[indx + i].adjusted_weight;
+
+ const f_pixel previous_center = bv[bi].color;
+ bv[bi].colors = break_at;
+ bv[bi].sum = lowersum;
+ bv[bi].color = averagepixels(bv[bi].colors, &achv[bv[bi].ind], min_opaque_val, previous_center);
+ bv[bi].total_error = -1;
+ bv[bi].variance = box_variance(achv, &bv[bi]);
+ bv[bi].max_error = box_max_error(achv, &bv[bi]);
+ bv[boxes].ind = indx + break_at;
+ bv[boxes].colors = clrs - break_at;
+ bv[boxes].sum = sm - lowersum;
+ bv[boxes].color = averagepixels(bv[boxes].colors, &achv[bv[boxes].ind], min_opaque_val, previous_center);
+ bv[boxes].total_error = -1;
+ bv[boxes].variance = box_variance(achv, &bv[boxes]);
+ bv[boxes].max_error = box_max_error(achv, &bv[boxes]);
+
+ ++boxes;
+
+ if (total_box_error_below_target(target_mse, bv, boxes, hist)) {
+ break;
+ }
+ }
+
+ colormap *map = pam_colormap(boxes, malloc, free);
+ set_colormap_from_boxes(map, bv, boxes, achv);
+
+ map->subset_palette = representative_subset;
+ adjust_histogram(achv, map, bv, boxes);
+
+ return map;
+}
+
+static void set_colormap_from_boxes(colormap *map, struct box* bv, unsigned int boxes, hist_item *achv)
+{
+ /*
+ ** Ok, we've got enough boxes. Now choose a representative color for
+ ** each box. There are a number of possible ways to make this choice.
+ ** One would be to choose the center of the box; this ignores any structure
+ ** within the boxes. Another method would be to average all the colors in
+ ** the box - this is the method specified in Heckbert's paper.
+ */
+
+ for(unsigned int bi = 0; bi < boxes; ++bi) {
+ map->palette[bi].acolor = bv[bi].color;
+
+ /* store total color popularity (perceptual_weight is approximation of it) */
+ map->palette[bi].popularity = 0;
+ for(unsigned int i=bv[bi].ind; i < bv[bi].ind+bv[bi].colors; i++) {
+ map->palette[bi].popularity += achv[i].perceptual_weight;
+ }
+ }
+}
+
+/* increase histogram popularity by difference from the final color (this is used as part of feedback loop) */
+static void adjust_histogram(hist_item *achv, const colormap *map, const struct box* bv, unsigned int boxes)
+{
+ for(unsigned int bi = 0; bi < boxes; ++bi) {
+ for(unsigned int i=bv[bi].ind; i < bv[bi].ind+bv[bi].colors; i++) {
+ achv[i].adjusted_weight *= sqrt(1.0 +colordifference(map->palette[bi].acolor, achv[i].acolor)/4.0);
+ achv[i].tmp.likely_colormap_index = bi;
+ }
+ }
+}
+
+static f_pixel averagepixels(unsigned int clrs, const hist_item achv[], const float min_opaque_val, const f_pixel center)
+{
+ double r = 0, g = 0, b = 0, a = 0, new_a=0, sum = 0;
+ float maxa = 0;
+
+ // first find final opacity in order to blend colors at that opacity
+ for(unsigned int i = 0; i < clrs; ++i) {
+ const f_pixel px = achv[i].acolor;
+ new_a += px.a * achv[i].adjusted_weight;
+ sum += achv[i].adjusted_weight;
+
+ /* find if there are opaque colors, in case we're supposed to preserve opacity exactly (ie_bug) */
+ if (px.a > maxa) maxa = px.a;
+ }
+
+ if (sum) new_a /= sum;
+
+ /** if there was at least one completely opaque color, "round" final color to opaque */
+ if (new_a >= min_opaque_val && maxa >= (255.0/256.0)) new_a = 1;
+
+ sum=0;
+ // reverse iteration for cache locality with previous loop
+ for(int i = clrs-1; i >= 0; i--) {
+ double tmp, weight = 1.0f;
+ f_pixel px = achv[i].acolor;
+
+ /* give more weight to colors that are further away from average
+ this is intended to prevent desaturation of images and fading of whites
+ */
+ tmp = (center.r - px.r);
+ weight += tmp*tmp;
+ tmp = (center.g - px.g);
+ weight += tmp*tmp;
+ tmp = (center.b - px.b);
+ weight += tmp*tmp;
+
+ weight *= achv[i].adjusted_weight;
+ sum += weight;
+
+ if (px.a) {
+ px.r /= px.a;
+ px.g /= px.a;
+ px.b /= px.a;
+ }
+
+ r += px.r * new_a * weight;
+ g += px.g * new_a * weight;
+ b += px.b * new_a * weight;
+ a += new_a * weight;
+ }
+
+ if (sum) {
+ a /= sum;
+ r /= sum;
+ g /= sum;
+ b /= sum;
+ }
+
+ assert(!isnan(r) && !isnan(g) && !isnan(b) && !isnan(a));
+
+ return (f_pixel){.r=r, .g=g, .b=b, .a=a};
+}
diff --git a/src/drivers/libimagequant/mediancut.h b/src/drivers/libimagequant/mediancut.h
new file mode 100644
index 0000000..e615c8d
--- /dev/null
+++ b/src/drivers/libimagequant/mediancut.h
@@ -0,0 +1,2 @@
+
+LIQ_PRIVATE colormap *mediancut(histogram *hist, const float min_opaque_val, unsigned int newcolors, const double target_mse, const double max_mse, void* (*malloc)(size_t), void (*free)(void*));
diff --git a/src/drivers/libimagequant/mempool.c b/src/drivers/libimagequant/mempool.c
new file mode 100644
index 0000000..032d80a
--- /dev/null
+++ b/src/drivers/libimagequant/mempool.c
@@ -0,0 +1,63 @@
+
+#include "libimagequant.h"
+#include "mempool.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#define ALIGN_MASK 15UL
+#define MEMPOOL_RESERVED ((sizeof(struct mempool)+ALIGN_MASK) & ~ALIGN_MASK)
+
+struct mempool {
+ unsigned int used, size;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+ struct mempool *next;
+};
+LIQ_PRIVATE void* mempool_create(mempool *mptr, const unsigned int size, unsigned int max_size, void* (*malloc)(size_t), void (*free)(void*))
+{
+ if (*mptr && ((*mptr)->used+size) <= (*mptr)->size) {
+ unsigned int prevused = (*mptr)->used;
+ (*mptr)->used += (size+15UL) & ~0xFUL;
+ return ((char*)(*mptr)) + prevused;
+ }
+
+ mempool old = *mptr;
+ if (!max_size) max_size = (1<<17);
+ max_size = size+ALIGN_MASK > max_size ? size+ALIGN_MASK : max_size;
+
+ *mptr = malloc(MEMPOOL_RESERVED + max_size);
+ if (!*mptr) return NULL;
+ **mptr = (struct mempool){
+ .malloc = malloc,
+ .free = free,
+ .size = MEMPOOL_RESERVED + max_size,
+ .used = sizeof(struct mempool),
+ .next = old,
+ };
+ uintptr_t mptr_used_start = (uintptr_t)(*mptr) + (*mptr)->used;
+ (*mptr)->used += (ALIGN_MASK + 1 - (mptr_used_start & ALIGN_MASK)) & ALIGN_MASK; // reserve bytes required to make subsequent allocations aligned
+ assert(!(((uintptr_t)(*mptr) + (*mptr)->used) & ALIGN_MASK));
+
+ return mempool_alloc(mptr, size, size);
+}
+
+LIQ_PRIVATE void* mempool_alloc(mempool *mptr, unsigned int size, unsigned int max_size)
+{
+ if (((*mptr)->used+size) <= (*mptr)->size) {
+ unsigned int prevused = (*mptr)->used;
+ (*mptr)->used += (size + ALIGN_MASK) & ~ALIGN_MASK;
+ return ((char*)(*mptr)) + prevused;
+ }
+
+ return mempool_create(mptr, size, max_size, (*mptr)->malloc, (*mptr)->free);
+}
+
+LIQ_PRIVATE void mempool_destroy(mempool m)
+{
+ while (m) {
+ mempool next = m->next;
+ m->free(m);
+ m = next;
+ }
+}
diff --git a/src/drivers/libimagequant/mempool.h b/src/drivers/libimagequant/mempool.h
new file mode 100644
index 0000000..e61b8dd
--- /dev/null
+++ b/src/drivers/libimagequant/mempool.h
@@ -0,0 +1,13 @@
+#ifndef MEMPOOL_H
+#define MEMPOOL_H
+
+#include <stddef.h>
+
+struct mempool;
+typedef struct mempool *mempool;
+
+LIQ_PRIVATE void* mempool_create(mempool *mptr, unsigned int size, unsigned int capacity, void* (*malloc)(size_t), void (*free)(void*));
+LIQ_PRIVATE void* mempool_alloc(mempool *mptr, unsigned int size, unsigned int capacity);
+LIQ_PRIVATE void mempool_destroy(mempool m);
+
+#endif
diff --git a/src/drivers/libimagequant/nearest.c b/src/drivers/libimagequant/nearest.c
new file mode 100644
index 0000000..e0a14d9
--- /dev/null
+++ b/src/drivers/libimagequant/nearest.c
@@ -0,0 +1,241 @@
+
+#include "libimagequant.h"
+#include "pam.h"
+#include "nearest.h"
+#include "mempool.h"
+#include <stdlib.h>
+
+struct sorttmp {
+ float radius;
+ unsigned int index;
+};
+
+struct head {
+ // colors less than radius away from vantage_point color will have best match in candidates
+ f_pixel vantage_point;
+ float radius;
+ unsigned int num_candidates;
+ f_pixel *candidates_color;
+ unsigned short *candidates_index;
+};
+
+struct nearest_map {
+ const colormap *map;
+ float nearest_other_color_dist[256];
+ mempool mempool;
+ struct head heads[];
+};
+
+static unsigned int find_slow(const f_pixel px, const colormap *map)
+{
+ unsigned int best=0;
+ float bestdiff = colordifference(px, map->palette[0].acolor);
+
+ for(unsigned int i=1; i < map->colors; i++) {
+ float diff = colordifference(px, map->palette[i].acolor);
+ if (diff < bestdiff) {
+ best = i;
+ bestdiff = diff;
+ }
+ }
+ return best;
+}
+
+static float distance_from_nearest_other_color(const colormap *map, const unsigned int i)
+{
+ float second_best=MAX_DIFF;
+ for(unsigned int j=0; j < map->colors; j++) {
+ if (i == j) continue;
+ float diff = colordifference(map->palette[i].acolor, map->palette[j].acolor);
+ if (diff <= second_best) {
+ second_best = diff;
+ }
+ }
+ return second_best;
+}
+
+static int compareradius(const void *ap, const void *bp)
+{
+ float a = ((const struct sorttmp*)ap)->radius;
+ float b = ((const struct sorttmp*)bp)->radius;
+ return a > b ? 1 : (a < b ? -1 : 0);
+}
+
+static struct head build_head(f_pixel px, const colormap *map, unsigned int num_candidates, mempool *m, float error_margin, bool skip_index[], unsigned int *skipped)
+{
+ struct sorttmp colors[map->colors];
+ unsigned int colorsused=0;
+
+ for(unsigned int i=0; i < map->colors; i++) {
+ if (skip_index[i]) continue; // colors in skip_index have been eliminated already in previous heads
+ colors[colorsused].index = i;
+ colors[colorsused].radius = colordifference(px, map->palette[i].acolor);
+ colorsused++;
+ }
+
+ qsort(&colors, colorsused, sizeof(colors[0]), compareradius);
+ assert(colorsused < 2 || colors[0].radius <= colors[1].radius); // closest first
+
+ num_candidates = MIN(colorsused, num_candidates);
+
+ struct head h = {
+ .candidates_color = mempool_alloc(m, num_candidates * sizeof(h.candidates_color[0]), 0),
+ .candidates_index = mempool_alloc(m, num_candidates * sizeof(h.candidates_index[0]), 0),
+ .vantage_point = px,
+ .num_candidates = num_candidates,
+ };
+ for(unsigned int i=0; i < num_candidates; i++) {
+ h.candidates_color[i] = map->palette[colors[i].index].acolor;
+ h.candidates_index[i] = colors[i].index;
+ }
+ // if all colors within this radius are included in candidates, then there cannot be any other better match
+ // farther away from the vantage point than half of the radius. Due to alpha channel must assume pessimistic radius.
+ h.radius = min_colordifference(px, h.candidates_color[num_candidates-1])/4.0f; // /4 = half of radius, but radius is squared
+
+ for(unsigned int i=0; i < num_candidates; i++) {
+ // divide again as that's matching certain subset within radius-limited subset
+ // - 1/256 is a tolerance for miscalculation (seems like colordifference isn't exact)
+ if (colors[i].radius < h.radius/4.f - error_margin) {
+ skip_index[colors[i].index]=true;
+ (*skipped)++;
+ }
+ }
+ return h;
+}
+
+static colormap *get_subset_palette(const colormap *map)
+{
+ if (map->subset_palette) {
+ return map->subset_palette;
+ }
+
+ unsigned int subset_size = (map->colors+3)/4;
+ colormap *subset_palette = pam_colormap(subset_size, map->malloc, map->free);
+
+ for(unsigned int i=0; i < subset_size; i++) {
+ subset_palette->palette[i] = map->palette[i];
+ }
+
+ return subset_palette;
+}
+
+LIQ_PRIVATE struct nearest_map *nearest_init(const colormap *map, bool fast)
+{
+ colormap *subset_palette = get_subset_palette(map);
+ const unsigned int num_vantage_points = map->colors > 16 ? MIN(map->colors/4, subset_palette->colors) : 0;
+ const unsigned long heads_size = sizeof(struct head) * (num_vantage_points+1); // +1 is fallback head
+
+ const unsigned long mempool_size = (sizeof(f_pixel) + sizeof(unsigned int)) * subset_palette->colors * map->colors/5 + (1<<14);
+ mempool m = NULL;
+ struct nearest_map *centroids = mempool_create(&m, sizeof(*centroids) + heads_size /* heads array is appended to it */, mempool_size, map->malloc, map->free);
+ centroids->mempool = m;
+
+ for(unsigned int i=0; i < map->colors; i++) {
+ const float dist = distance_from_nearest_other_color(map,i);
+ centroids->nearest_other_color_dist[i] = dist / 4.f; // half of squared distance
+ }
+
+ centroids->map = map;
+
+ unsigned int skipped=0;
+ assert(map->colors > 0);
+ bool skip_index[map->colors]; for(unsigned int j=0; j < map->colors; j++) skip_index[j]=false;
+
+ // floats and colordifference calculations are not perfect
+ const float error_margin = fast ? 0 : 8.f/256.f/256.f;
+ unsigned int h=0;
+ for(; h < num_vantage_points; h++) {
+ unsigned int num_candiadtes = 1+(map->colors - skipped)/((1+num_vantage_points-h)/2);
+
+ centroids->heads[h] = build_head(subset_palette->palette[h].acolor, map, num_candiadtes, ¢roids->mempool, error_margin, skip_index, &skipped);
+ if (centroids->heads[h].num_candidates == 0) {
+ break;
+ }
+ }
+
+ // assumption that there is no better color within radius of vantage point color
+ // holds true only for colors within convex hull formed by palette colors.
+ // since finding proper convex hull is more than a few lines, this
+ // is a cheap shot at finding just few key points.
+ const f_pixel extrema[] = {
+ {.a=0,0,0,0},
+
+ {.a=.5,0,0,0}, {.a=.5,1,0,0},
+ {.a=.5,0,0,1}, {.a=.5,1,0,1},
+ {.a=.5,0,1,0}, {.a=.5,1,1,0},
+ {.a=.5,0,1,1}, {.a=.5,1,1,1},
+
+ {.a=1,0,0,0}, {.a=1,1,0,0},
+ {.a=1,0,0,1}, {.a=1,1,0,1},
+ {.a=1,0,1,0}, {.a=1,1,1,0},
+ {.a=1,0,1,1}, {.a=1,1,1,1},
+
+ {.a=1,.5, 0, 0}, {.a=1, 0,.5, 0}, {.a=1, 0, 0, .5},
+ {.a=1,.5, 0, 1}, {.a=1, 0,.5, 1}, {.a=1, 0, 1, .5},
+ {.a=1,.5, 1, 0}, {.a=1, 1,.5, 0}, {.a=1, 1, 0, .5},
+ {.a=1,.5, 1, 1}, {.a=1, 1,.5, 1}, {.a=1, 1, 1, .5},
+ };
+ for(unsigned int i=0; i < sizeof(extrema)/sizeof(extrema[0]); i++) {
+ skip_index[find_slow(extrema[i], map)]=0;
+ }
+
+ centroids->heads[h] = build_head((f_pixel){0,0,0,0}, map, map->colors, ¢roids->mempool, error_margin, skip_index, &skipped);
+ centroids->heads[h].radius = MAX_DIFF;
+
+ // get_subset_palette could have created a copy
+ if (subset_palette != map->subset_palette) {
+ pam_freecolormap(subset_palette);
+ }
+
+ return centroids;
+}
+
+LIQ_PRIVATE unsigned int nearest_search(const struct nearest_map *centroids, const f_pixel px, int likely_colormap_index, const float min_opaque_val, float *diff)
+{
+ const bool iebug = px.a > min_opaque_val;
+
+ const struct head *const heads = centroids->heads;
+
+ assert(likely_colormap_index < centroids->map->colors);
+ const float guess_diff = colordifference(centroids->map->palette[likely_colormap_index].acolor, px);
+ if (guess_diff < centroids->nearest_other_color_dist[likely_colormap_index]) {
+ if (diff) *diff = guess_diff;
+ return likely_colormap_index;
+ }
+
+ for(unsigned int i=0; /* last head will always be selected */ ; i++) {
+ float vantage_point_dist = colordifference(px, heads[i].vantage_point);
+
+ if (vantage_point_dist <= heads[i].radius) {
+ assert(heads[i].num_candidates);
+ unsigned int ind=0;
+ float dist = colordifference(px, heads[i].candidates_color[0]);
+
+ /* penalty for making holes in IE */
+ if (iebug && heads[i].candidates_color[0].a < 1) {
+ dist += 1.f/1024.f;
+ }
+
+ for(unsigned int j=1; j < heads[i].num_candidates; j++) {
+ float newdist = colordifference(px, heads[i].candidates_color[j]);
+
+ /* penalty for making holes in IE */
+ if (iebug && heads[i].candidates_color[j].a < 1) {
+ newdist += 1.f/1024.f;
+ }
+
+ if (newdist < dist) {
+ dist = newdist;
+ ind = j;
+ }
+ }
+ if (diff) *diff = dist;
+ return heads[i].candidates_index[ind];
+ }
+ }
+}
+
+LIQ_PRIVATE void nearest_free(struct nearest_map *centroids)
+{
+ mempool_destroy(centroids->mempool);
+}
diff --git a/src/drivers/libimagequant/nearest.h b/src/drivers/libimagequant/nearest.h
new file mode 100644
index 0000000..9745d95
--- /dev/null
+++ b/src/drivers/libimagequant/nearest.h
@@ -0,0 +1,8 @@
+//
+// nearest.h
+// pngquant
+//
+struct nearest_map;
+LIQ_PRIVATE struct nearest_map *nearest_init(const colormap *palette, const bool fast);
+LIQ_PRIVATE unsigned int nearest_search(const struct nearest_map *map, const f_pixel px, const int palette_index_guess, const float min_opaque, float *diff);
+LIQ_PRIVATE void nearest_free(struct nearest_map *map);
diff --git a/src/drivers/libimagequant/pam.c b/src/drivers/libimagequant/pam.c
new file mode 100644
index 0000000..647a8aa
--- /dev/null
+++ b/src/drivers/libimagequant/pam.c
@@ -0,0 +1,278 @@
+/* pam.c - pam (portable alpha map) utility library
+**
+** Copyright (C) 1989, 1991 by Jef Poskanzer.
+** Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by
+** Stefan Schneider.
+** © 2009-2013 by Kornel Lesinski.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "libimagequant.h"
+#include "pam.h"
+#include "mempool.h"
+
+LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const rgba_pixel *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map)
+{
+ const unsigned int maxacolors = acht->maxcolors, ignorebits = acht->ignorebits;
+ const unsigned int channel_mask = 255U>>ignorebits<<ignorebits;
+ const unsigned int channel_hmask = (255U>>ignorebits) ^ 0xFFU;
+ const unsigned int posterize_mask = channel_mask << 24 | channel_mask << 16 | channel_mask << 8 | channel_mask;
+ const unsigned int posterize_high_mask = channel_hmask << 24 | channel_hmask << 16 | channel_hmask << 8 | channel_hmask;
+ struct acolorhist_arr_head *const buckets = acht->buckets;
+
+ unsigned int colors = acht->colors;
+ const unsigned int hash_size = acht->hash_size;
+
+ const unsigned int stacksize = sizeof(acht->freestack)/sizeof(acht->freestack[0]);
+ struct acolorhist_arr_item **freestack = acht->freestack;
+ unsigned int freestackp=acht->freestackp;
+
+ /* Go through the entire image, building a hash table of colors. */
+ for(unsigned int row = 0; row < rows; ++row) {
+
+ float boost=1.0;
+ for(unsigned int col = 0; col < cols; ++col) {
+ if (importance_map) {
+ boost = 0.5f+ (double)*importance_map++/255.f;
+ }
+
+ // RGBA color is casted to long for easier hasing/comparisons
+ union rgba_as_int px = {pixels[row][col]};
+ unsigned int hash;
+ if (!px.rgba.a) {
+ // "dirty alpha" has different RGBA values that end up being the same fully transparent color
+ px.l=0; hash=0;
+ } else {
+ // mask posterizes all 4 channels in one go
+ px.l = (px.l & posterize_mask) | ((px.l & posterize_high_mask) >> (8-ignorebits));
+ // fancier hashing algorithms didn't improve much
+ hash = px.l % hash_size;
+ }
+
+ /* head of the hash function stores first 2 colors inline (achl->used = 1..2),
+ to reduce number of allocations of achl->other_items.
+ */
+ struct acolorhist_arr_head *achl = &buckets[hash];
+ if (achl->inline1.color.l == px.l && achl->used) {
+ achl->inline1.perceptual_weight += boost;
+ continue;
+ }
+ if (achl->used) {
+ if (achl->used > 1) {
+ if (achl->inline2.color.l == px.l) {
+ achl->inline2.perceptual_weight += boost;
+ continue;
+ }
+ // other items are stored as an array (which gets reallocated if needed)
+ struct acolorhist_arr_item *other_items = achl->other_items;
+ unsigned int i = 0;
+ for (; i < achl->used-2; i++) {
+ if (other_items[i].color.l == px.l) {
+ other_items[i].perceptual_weight += boost;
+ goto continue_outer_loop;
+ }
+ }
+
+ // the array was allocated with spare items
+ if (i < achl->capacity) {
+ other_items[i] = (struct acolorhist_arr_item){
+ .color = px,
+ .perceptual_weight = boost,
+ };
+ achl->used++;
+ ++colors;
+ continue;
+ }
+
+ if (++colors > maxacolors) {
+ acht->colors = colors;
+ acht->freestackp = freestackp;
+ return false;
+ }
+
+ struct acolorhist_arr_item *new_items;
+ unsigned int capacity;
+ if (!other_items) { // there was no array previously, alloc "small" array
+ capacity = 8;
+ if (freestackp <= 0) {
+ // estimate how many colors are going to be + headroom
+ const int mempool_size = ((acht->rows + rows-row) * 2 * colors / (acht->rows + row + 1) + 1024) * sizeof(struct acolorhist_arr_item);
+ new_items = mempool_alloc(&acht->mempool, sizeof(struct acolorhist_arr_item)*capacity, mempool_size);
+ } else {
+ // freestack stores previously freed (reallocated) arrays that can be reused
+ // (all pesimistically assumed to be capacity = 8)
+ new_items = freestack[--freestackp];
+ }
+ } else {
+ // simply reallocs and copies array to larger capacity
+ capacity = achl->capacity*2 + 16;
+ if (freestackp < stacksize-1) {
+ freestack[freestackp++] = other_items;
+ }
+ const int mempool_size = ((acht->rows + rows-row) * 2 * colors / (acht->rows + row + 1) + 32*capacity) * sizeof(struct acolorhist_arr_item);
+ new_items = mempool_alloc(&acht->mempool, sizeof(struct acolorhist_arr_item)*capacity, mempool_size);
+ if (!new_items) return false;
+ memcpy(new_items, other_items, sizeof(other_items[0])*achl->capacity);
+ }
+
+ achl->other_items = new_items;
+ achl->capacity = capacity;
+ new_items[i] = (struct acolorhist_arr_item){
+ .color = px,
+ .perceptual_weight = boost,
+ };
+ achl->used++;
+ } else {
+ // these are elses for first checks whether first and second inline-stored colors are used
+ achl->inline2.color.l = px.l;
+ achl->inline2.perceptual_weight = boost;
+ achl->used = 2;
+ ++colors;
+ }
+ } else {
+ achl->inline1.color.l = px.l;
+ achl->inline1.perceptual_weight = boost;
+ achl->used = 1;
+ ++colors;
+ }
+
+ continue_outer_loop:;
+ }
+
+ }
+ acht->colors = colors;
+ acht->cols = cols;
+ acht->rows += rows;
+ acht->freestackp = freestackp;
+ return true;
+}
+
+LIQ_PRIVATE struct acolorhash_table *pam_allocacolorhash(unsigned int maxcolors, unsigned int surface, unsigned int ignorebits, void* (*malloc)(size_t), void (*free)(void*))
+{
+ const unsigned int estimated_colors = MIN(maxcolors, surface/(ignorebits + (surface > 512*512 ? 5 : 4)));
+ const unsigned int hash_size = estimated_colors < 66000 ? 6673 : (estimated_colors < 200000 ? 12011 : 24019);
+
+ mempool m = NULL;
+ const unsigned int buckets_size = hash_size * sizeof(struct acolorhist_arr_head);
+ const unsigned int mempool_size = sizeof(struct acolorhash_table) + buckets_size + estimated_colors * sizeof(struct acolorhist_arr_item);
+ struct acolorhash_table *t = mempool_create(&m, sizeof(*t) + buckets_size, mempool_size, malloc, free);
+ if (!t) return NULL;
+ *t = (struct acolorhash_table){
+ .mempool = m,
+ .hash_size = hash_size,
+ .maxcolors = maxcolors,
+ .ignorebits = ignorebits,
+ };
+ memset(t->buckets, 0, hash_size * sizeof(struct acolorhist_arr_head));
+ return t;
+}
+
+#define PAM_ADD_TO_HIST(entry) { \
+ hist->achv[j].acolor = to_f(gamma_lut, entry.color.rgba); \
+ total_weight += hist->achv[j].adjusted_weight = hist->achv[j].perceptual_weight = MIN(entry.perceptual_weight, max_perceptual_weight); \
+ ++j; \
+}
+
+LIQ_PRIVATE histogram *pam_acolorhashtoacolorhist(const struct acolorhash_table *acht, const double gamma, void* (*malloc)(size_t), void (*free)(void*))
+{
+ histogram *hist = malloc(sizeof(hist[0]));
+ if (!hist || !acht) return NULL;
+ *hist = (histogram){
+ .achv = malloc(acht->colors * sizeof(hist->achv[0])),
+ .size = acht->colors,
+ .free = free,
+ .ignorebits = acht->ignorebits,
+ };
+ if (!hist->achv) return NULL;
+
+ float gamma_lut[256];
+ to_f_set_gamma(gamma_lut, gamma);
+
+ /* Limit perceptual weight to 1/10th of the image surface area to prevent
+ a single color from dominating all others. */
+ float max_perceptual_weight = 0.1f * acht->cols * acht->rows;
+ double total_weight = 0;
+
+ for(unsigned int j=0, i=0; i < acht->hash_size; ++i) {
+ const struct acolorhist_arr_head *const achl = &acht->buckets[i];
+ if (achl->used) {
+ PAM_ADD_TO_HIST(achl->inline1);
+
+ if (achl->used > 1) {
+ PAM_ADD_TO_HIST(achl->inline2);
+
+ for(unsigned int k=0; k < achl->used-2; k++) {
+ PAM_ADD_TO_HIST(achl->other_items[k]);
+ }
+ }
+ }
+ }
+
+ hist->total_perceptual_weight = total_weight;
+ return hist;
+}
+
+
+LIQ_PRIVATE void pam_freeacolorhash(struct acolorhash_table *acht)
+{
+ mempool_destroy(acht->mempool);
+}
+
+LIQ_PRIVATE void pam_freeacolorhist(histogram *hist)
+{
+ hist->free(hist->achv);
+ hist->free(hist);
+}
+
+LIQ_PRIVATE colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*))
+{
+ assert(colors > 0 && colors < 65536);
+
+ colormap *map;
+ const size_t colors_size = colors * sizeof(map->palette[0]);
+ map = malloc(sizeof(colormap) + colors_size);
+ if (!map) return NULL;
+ *map = (colormap){
+ .malloc = malloc,
+ .free = free,
+ .subset_palette = NULL,
+ .colors = colors,
+ };
+ memset(map->palette, 0, colors_size);
+ return map;
+}
+
+LIQ_PRIVATE colormap *pam_duplicate_colormap(colormap *map)
+{
+ colormap *dupe = pam_colormap(map->colors, map->malloc, map->free);
+ for(unsigned int i=0; i < map->colors; i++) {
+ dupe->palette[i] = map->palette[i];
+ }
+ if (map->subset_palette) {
+ dupe->subset_palette = pam_duplicate_colormap(map->subset_palette);
+ }
+ return dupe;
+}
+
+LIQ_PRIVATE void pam_freecolormap(colormap *c)
+{
+ if (c->subset_palette) pam_freecolormap(c->subset_palette);
+ c->free(c);
+}
+
+LIQ_PRIVATE void to_f_set_gamma(float gamma_lut[], const double gamma)
+{
+ for(int i=0; i < 256; i++) {
+ gamma_lut[i] = pow((double)i/255.0, internal_gamma/gamma);
+ }
+}
+
diff --git a/src/drivers/libimagequant/pam.h b/src/drivers/libimagequant/pam.h
new file mode 100644
index 0000000..835f852
--- /dev/null
+++ b/src/drivers/libimagequant/pam.h
@@ -0,0 +1,290 @@
+/* pam.h - pam (portable alpha map) utility library
+ **
+ ** Colormap routines.
+ **
+ ** Copyright (C) 1989, 1991 by Jef Poskanzer.
+ ** Copyright (C) 1997 by Greg Roelofs.
+ **
+ ** Permission to use, copy, modify, and distribute this software and its
+ ** documentation for any purpose and without fee is hereby granted, provided
+ ** that the above copyright notice appear in all copies and that both that
+ ** copyright notice and this permission notice appear in supporting
+ ** documentation. This software is provided "as is" without express or
+ ** implied warranty.
+ */
+
+#ifndef PAM_H
+#define PAM_H
+
+#include <math.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b)? (a) : (b))
+# define MIN(a,b) ((a) < (b)? (a) : (b))
+#endif
+
+#define MAX_DIFF 1e20
+
+#ifndef USE_SSE
+# if defined(__SSE__) && (defined(WIN32) || defined(__WIN32__))
+# define USE_SSE 1
+# else
+# define USE_SSE 0
+# endif
+#endif
+
+#if USE_SSE
+# include <xmmintrin.h>
+# ifdef _MSC_VER
+# include <intrin.h>
+# define SSE_ALIGN
+# else
+# define SSE_ALIGN __attribute__ ((aligned (16)))
+# if defined(__i386__) && defined(__PIC__)
+# define cpuid(func,ax,bx,cx,dx)\
+ __asm__ __volatile__ ( \
+ "push %%ebx\n" \
+ "cpuid\n" \
+ "mov %%ebx, %1\n" \
+ "pop %%ebx\n" \
+ : "=a" (ax), "=r" (bx), "=c" (cx), "=d" (dx) \
+ : "a" (func));
+# else
+# define cpuid(func,ax,bx,cx,dx)\
+ __asm__ __volatile__ ("cpuid":\
+ "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
+# endif
+#endif
+#else
+# define SSE_ALIGN
+#endif
+
+#if defined(__GNUC__) || defined (__llvm__)
+#define ALWAYS_INLINE __attribute__((always_inline)) inline
+#define NEVER_INLINE __attribute__ ((noinline))
+#elif defined(_MSC_VER)
+#define inline __inline
+#define restrict __restrict
+#define ALWAYS_INLINE __forceinline
+#define NEVER_INLINE __declspec(noinline)
+#else
+#define ALWAYS_INLINE inline
+#define NEVER_INLINE
+#endif
+
+/* from pam.h */
+
+typedef struct {
+ unsigned char r, g, b, a;
+} rgba_pixel;
+
+typedef struct {
+ float a, r, g, b;
+} SSE_ALIGN f_pixel;
+
+static const double internal_gamma = 0.5499;
+
+LIQ_PRIVATE void to_f_set_gamma(float gamma_lut[], const double gamma);
+
+/**
+ Converts 8-bit color to internal gamma and premultiplied alpha.
+ (premultiplied color space is much better for blending of semitransparent colors)
+ */
+ALWAYS_INLINE static f_pixel to_f(const float gamma_lut[], const rgba_pixel px);
+inline static f_pixel to_f(const float gamma_lut[], const rgba_pixel px)
+{
+ float a = px.a/255.f;
+
+ return (f_pixel) {
+ .a = a,
+ .r = gamma_lut[px.r]*a,
+ .g = gamma_lut[px.g]*a,
+ .b = gamma_lut[px.b]*a,
+ };
+}
+
+inline static rgba_pixel to_rgb(const float gamma, const f_pixel px)
+{
+ if (px.a < 1.f/256.f) {
+ return (rgba_pixel){0,0,0,0};
+ }
+
+ float r = px.r / px.a,
+ g = px.g / px.a,
+ b = px.b / px.a,
+ a = px.a;
+
+ r = powf(r, gamma/internal_gamma);
+ g = powf(g, gamma/internal_gamma);
+ b = powf(b, gamma/internal_gamma);
+
+ // 256, because numbers are in range 1..255.9999… rounded down
+ r *= 256.f;
+ g *= 256.f;
+ b *= 256.f;
+ a *= 256.f;
+
+ return (rgba_pixel){
+ .r = r>=255.f ? 255 : r,
+ .g = g>=255.f ? 255 : g,
+ .b = b>=255.f ? 255 : b,
+ .a = a>=255.f ? 255 : a,
+ };
+}
+
+ALWAYS_INLINE static double colordifference_ch(const double x, const double y, const double alphas);
+inline static double colordifference_ch(const double x, const double y, const double alphas)
+{
+ // maximum of channel blended on white, and blended on black
+ // premultiplied alpha and backgrounds 0/1 shorten the formula
+ const double black = x-y, white = black+alphas;
+ return black*black + white*white;
+}
+
+ALWAYS_INLINE static float colordifference_stdc(const f_pixel px, const f_pixel py);
+inline static float colordifference_stdc(const f_pixel px, const f_pixel py)
+{
+ // px_b.rgb = px.rgb + 0*(1-px.a) // blend px on black
+ // px_b.a = px.a + 1*(1-px.a)
+ // px_w.rgb = px.rgb + 1*(1-px.a) // blend px on white
+ // px_w.a = px.a + 1*(1-px.a)
+
+ // px_b.rgb = px.rgb // difference same as in opaque RGB
+ // px_b.a = 1
+ // px_w.rgb = px.rgb - px.a // difference simplifies to formula below
+ // px_w.a = 1
+
+ // (px.rgb - px.a) - (py.rgb - py.a)
+ // (px.rgb - py.rgb) + (py.a - px.a)
+
+ const double alphas = py.a-px.a;
+ return colordifference_ch(px.r, py.r, alphas) +
+ colordifference_ch(px.g, py.g, alphas) +
+ colordifference_ch(px.b, py.b, alphas);
+}
+
+ALWAYS_INLINE static double min_colordifference_ch(const double x, const double y, const double alphas);
+inline static double min_colordifference_ch(const double x, const double y, const double alphas)
+{
+ const double black = x-y, white = black+alphas;
+ return MIN(black*black , white*white) * 2.f;
+}
+
+/* least possible difference between colors (difference varies depending on background they're blended on) */
+ALWAYS_INLINE static float min_colordifference(const f_pixel px, const f_pixel py);
+inline static float min_colordifference(const f_pixel px, const f_pixel py)
+{
+ const double alphas = py.a-px.a;
+ return min_colordifference_ch(px.r, py.r, alphas) +
+ min_colordifference_ch(px.g, py.g, alphas) +
+ min_colordifference_ch(px.b, py.b, alphas);
+}
+
+ALWAYS_INLINE static float colordifference(f_pixel px, f_pixel py);
+inline static float colordifference(f_pixel px, f_pixel py)
+{
+#if USE_SSE
+ const __m128 vpx = _mm_load_ps((const float*)&px);
+ const __m128 vpy = _mm_load_ps((const float*)&py);
+
+ // y.a - x.a
+ __m128 alphas = _mm_sub_ss(vpy, vpx);
+ alphas = _mm_shuffle_ps(alphas,alphas,0); // copy first to all four
+
+ __m128 onblack = _mm_sub_ps(vpx, vpy); // x - y
+ __m128 onwhite = _mm_add_ps(onblack, alphas); // x - y + (y.a - x.a)
+
+ onblack = _mm_mul_ps(onblack, onblack);
+ onwhite = _mm_mul_ps(onwhite, onwhite);
+ const __m128 max = _mm_add_ps(onwhite, onblack);
+
+ // add rgb, not a
+ const __m128 maxhl = _mm_movehl_ps(max, max);
+ const __m128 tmp = _mm_add_ps(max, maxhl);
+ const __m128 sum = _mm_add_ss(maxhl, _mm_shuffle_ps(tmp, tmp, 1));
+
+ const float res = _mm_cvtss_f32(sum);
+ assert(fabs(res - colordifference_stdc(px,py)) < 0.001);
+ return res;
+#else
+ return colordifference_stdc(px,py);
+#endif
+}
+
+/* from pamcmap.h */
+union rgba_as_int {
+ rgba_pixel rgba;
+ unsigned int l;
+};
+
+typedef struct {
+ f_pixel acolor;
+ float adjusted_weight, // perceptual weight changed to tweak how mediancut selects colors
+ perceptual_weight; // number of pixels weighted by importance of different areas of the picture
+
+ float color_weight; // these two change every time histogram subset is sorted
+ union {
+ unsigned int sort_value;
+ unsigned char likely_colormap_index;
+ } tmp;
+} hist_item;
+
+typedef struct {
+ hist_item *achv;
+ void (*free)(void*);
+ double total_perceptual_weight;
+ unsigned int size;
+ unsigned int ignorebits;
+} histogram;
+
+typedef struct {
+ f_pixel acolor;
+ float popularity;
+} colormap_item;
+
+typedef struct colormap {
+ unsigned int colors;
+ void* (*malloc)(size_t);
+ void (*free)(void*);
+ struct colormap *subset_palette;
+ colormap_item palette[];
+} colormap;
+
+struct acolorhist_arr_item {
+ union rgba_as_int color;
+ float perceptual_weight;
+};
+
+struct acolorhist_arr_head {
+ unsigned int used, capacity;
+ struct {
+ union rgba_as_int color;
+ float perceptual_weight;
+ } inline1, inline2;
+ struct acolorhist_arr_item *other_items;
+};
+
+struct acolorhash_table {
+ struct mempool *mempool;
+ unsigned int ignorebits, maxcolors, colors, cols, rows;
+ unsigned int hash_size;
+ unsigned int freestackp;
+ struct acolorhist_arr_item *freestack[512];
+ struct acolorhist_arr_head buckets[];
+};
+
+LIQ_PRIVATE void pam_freeacolorhash(struct acolorhash_table *acht);
+LIQ_PRIVATE struct acolorhash_table *pam_allocacolorhash(unsigned int maxcolors, unsigned int surface, unsigned int ignorebits, void* (*malloc)(size_t), void (*free)(void*));
+LIQ_PRIVATE histogram *pam_acolorhashtoacolorhist(const struct acolorhash_table *acht, const double gamma, void* (*malloc)(size_t), void (*free)(void*));
+LIQ_PRIVATE bool pam_computeacolorhash(struct acolorhash_table *acht, const rgba_pixel *const pixels[], unsigned int cols, unsigned int rows, const unsigned char *importance_map);
+
+LIQ_PRIVATE void pam_freeacolorhist(histogram *h);
+
+LIQ_PRIVATE colormap *pam_colormap(unsigned int colors, void* (*malloc)(size_t), void (*free)(void*));
+LIQ_PRIVATE colormap *pam_duplicate_colormap(colormap *map);
+LIQ_PRIVATE void pam_freecolormap(colormap *c);
+
+#endif
diff --git a/src/drivers/libimagequant/pngquant.c b/src/drivers/libimagequant/pngquant.c
new file mode 100644
index 0000000..08851cc
--- /dev/null
+++ b/src/drivers/libimagequant/pngquant.c
@@ -0,0 +1,295 @@
+/* pngquant.c - quantize the colors in an alphamap down to a specified number
+**
+** Copyright (C) 1989, 1991 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+**
+** - - - -
+**
+** © 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
+** © 2009-2014 by Kornel Lesiński.
+**
+** 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.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "pngquant.h"
+
+void verbose_printf(struct pngquant_options *context, const char *fmt, ...)
+{
+ if (context->log_callback) {
+ va_list va;
+ va_start(va, fmt);
+ int required_space = vsnprintf(NULL, 0, fmt, va)+1; // +\0
+ va_end(va);
+
+ char buf[required_space];
+ va_start(va, fmt);
+ vsnprintf(buf, required_space, fmt, va);
+ va_end(va);
+
+ context->log_callback(context->liq, buf, context->log_callback_user_info);
+ }
+}
+
+
+pngquant_error pngquant_file(const char *filename, const char *outname, struct pngquant_options *options)
+{
+ pngquant_error retval = SUCCESS;
+ liq_image* input_image = NULL;
+ png24_image input_image_rwpng = {};
+
+ retval = read_image(options->liq, filename, options->using_stdin, &input_image_rwpng, &input_image, false, options->verbose);
+
+ int quality_percent = 90; // quality on 0-100 scale, updated upon successful remap
+ png8_image output_image = {};
+
+ if (SUCCESS == retval)
+ {
+ // when using image as source of a fixed palette the palette is extracted using regular quantization
+ liq_result *remap = liq_quantize_image(options->liq, options->fixed_palette_image ? options->fixed_palette_image : input_image);
+
+ if (remap) {
+ liq_set_output_gamma(remap, 0.45455); // fixed gamma ~2.2 for the web. PNG can't store exact 1/2.2
+ liq_set_dithering_level(remap, options->floyd);
+
+ retval = prepare_output_image(remap, input_image, &output_image);
+ if (SUCCESS == retval) {
+ if (LIQ_OK != liq_write_remapped_image_rows(remap, input_image, output_image.row_pointers)) {
+ retval = OUT_OF_MEMORY_ERROR;
+ }
+
+ set_palette(remap, &output_image);
+
+ double palette_error = liq_get_quantization_error(remap);
+ if (palette_error >= 0) {
+ quality_percent = liq_get_quantization_quality(remap);
+ //verbose_printf(options, " mapped image to new colors...MSE=%.3f (Q=%d)", palette_error, quality_percent);
+ }
+ }
+ liq_result_destroy(remap);
+ } else {
+ retval = TOO_LOW_QUALITY;
+ }
+ }
+
+ if (SUCCESS == retval) {
+ output_image.fast_compression = options->fast_compression;
+ output_image.chunks = input_image_rwpng.chunks;
+ input_image_rwpng.chunks = NULL;
+
+ retval = write_image(&output_image, NULL, outname, options);
+ }
+/*
+ if (options->using_stdout && keep_input_pixels && (TOO_LARGE_FILE == retval || TOO_LOW_QUALITY == retval)) {
+ // when outputting to stdout it'd be nasty to create 0-byte file
+ // so if quality is too low, output 24-bit original
+ pngquant_error write_retval = write_image(NULL, &input_image_rwpng, outname, options);
+ if (write_retval) {
+ retval = write_retval;
+ }
+ }
+*/
+ liq_image_destroy(input_image);
+ rwpng_free_image24(&input_image_rwpng);
+ rwpng_free_image8(&output_image);
+ return retval;
+}
+
+/**************************************************************************
+ *
+ */
+void set_palette(liq_result *result, png8_image *output_image)
+{
+ const liq_palette *palette = liq_get_palette(result);
+
+ // tRNS, etc.
+ output_image->num_palette = palette->count;
+ output_image->num_trans = 0;
+ for(unsigned int i=0; i < palette->count; i++) {
+ liq_color px = palette->entries[i];
+ if (px.a < 255) {
+ output_image->num_trans = i+1;
+ }
+ output_image->palette[i] = (png_color){.red=px.r, .green=px.g, .blue=px.b};
+ output_image->trans[i] = px.a;
+ }
+}
+
+
+/**************************************************************************
+ *
+ */
+char *temp_filename(const char *basename) {
+ size_t x = strlen(basename);
+
+ char *outname = (char *)malloc(x+1+4);
+ if (!outname) return NULL;
+
+ strcpy(outname, basename);
+ strcpy(outname+x, ".tmp");
+
+ return outname;
+}
+
+
+/**************************************************************************
+ *
+ */
+pngquant_error write_image(png8_image *output_image, png24_image *output_image24, const char *outname, struct pngquant_options *options)
+{
+ FILE *outfile;
+ char *tempname = NULL;
+
+ tempname = temp_filename(outname);
+ if (!tempname) return OUT_OF_MEMORY_ERROR;
+
+ if ((outfile = fopen(tempname, "wb")) == NULL) {
+ fprintf(stderr, " error: cannot open '%s' for writing\n", tempname);
+ free(tempname);
+ return CANT_WRITE_ERROR;
+ }
+
+ if (output_image) {
+ verbose_printf(options, " writing %d-color image as %s", output_image->num_palette, outname);
+ } else {
+ verbose_printf(options, " writing truecolor image as %s", outname);
+ }
+
+ pngquant_error retval;
+ if (output_image) {
+ retval = rwpng_write_image8(outfile, output_image);
+ } else {
+ retval = rwpng_write_image24(outfile, output_image24);
+ }
+
+ if (!options->using_stdout) {
+ fclose(outfile);
+
+ if (SUCCESS == retval) {
+ // Image has been written to a temporary file and then moved over destination.
+ // This makes replacement atomic and avoids damaging destination file on write error.
+ if (0 != rename(tempname, outname)) {
+ retval = CANT_WRITE_ERROR;
+ }
+ }
+
+ if (retval) {
+ unlink(tempname);
+ }
+ free(tempname);
+ }
+
+ if (retval && retval != TOO_LARGE_FILE) {
+ fprintf(stderr, " error: failed writing image to %s\n", outname);
+ }
+ return retval;
+}
+
+/**************************************************************************
+ *
+ */
+pngquant_error read_image(liq_attr *options, const char *filename, int using_stdin, png24_image *input_image_p, liq_image **liq_image_p, bool keep_input_pixels, bool verbose)
+{
+ FILE *infile;
+
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, " error: cannot open %s for reading\n", filename);
+ return READ_ERROR;
+ }
+
+ pngquant_error retval;
+ retval = rwpng_read_image24(infile, input_image_p, verbose);
+
+ fclose(infile);
+
+ if (retval) {
+ fprintf(stderr, " error: rwpng_read_image() error %d with file %s\n", retval, filename);
+ return retval;
+ }
+
+ *liq_image_p = liq_image_create_rgba_rows(options, (void**)input_image_p->row_pointers, input_image_p->width, input_image_p->height, input_image_p->gamma);
+
+ if (!*liq_image_p) {
+ return OUT_OF_MEMORY_ERROR;
+ }
+
+ if (!keep_input_pixels) {
+ if (LIQ_OK != liq_image_set_memory_ownership(*liq_image_p, LIQ_OWN_ROWS | LIQ_OWN_PIXELS)) {
+ return OUT_OF_MEMORY_ERROR;
+ }
+ input_image_p->row_pointers = NULL;
+ input_image_p->rgba_data = NULL;
+ }
+ return SUCCESS;
+}
+
+/**************************************************************************
+ *
+ */
+pngquant_error prepare_output_image(liq_result *result, liq_image *input_image, png8_image *output_image)
+{
+ output_image->width = liq_image_get_width(input_image);
+ output_image->height = liq_image_get_height(input_image);
+ output_image->gamma = liq_get_output_gamma(result);
+
+ /*
+ ** Step 3.7 [GRR]: allocate memory for the entire indexed image
+ */
+ output_image->indexed_data = (unsigned char *)malloc(output_image->height * output_image->width);
+ output_image->row_pointers = (unsigned char **)malloc(output_image->height * sizeof(output_image->row_pointers[0]));
+
+ if (!output_image->indexed_data || !output_image->row_pointers) {
+ return OUT_OF_MEMORY_ERROR;
+ }
+
+ for(unsigned int row = 0; row < output_image->height; ++row) {
+ output_image->row_pointers[row] = output_image->indexed_data + row*output_image->width;
+ }
+
+ const liq_palette *palette = liq_get_palette(result);
+ // tRNS, etc.
+ output_image->num_palette = palette->count;
+ output_image->num_trans = 0;
+ for(unsigned int i=0; i < palette->count; i++) {
+ if (palette->entries[i].a < 255) {
+ output_image->num_trans = i+1;
+ }
+ }
+ return SUCCESS;
+}
diff --git a/src/drivers/libimagequant/pngquant.h b/src/drivers/libimagequant/pngquant.h
new file mode 100644
index 0000000..929db15
--- /dev/null
+++ b/src/drivers/libimagequant/pngquant.h
@@ -0,0 +1,71 @@
+/* pngquant.c - quantize the colors in an alphamap down to a specified number
+**
+** Copyright (C) 1989, 1991 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+**
+** - - - -
+**
+** © 1997-2002 by Greg Roelofs; based on an idea by Stefan Schneider.
+** © 2009-2014 by Kornel Lesiński.
+**
+** 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.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "rwpng.h" /* typedefs, common macros, public prototypes */
+#include "libimagequant.h"
+
+struct pngquant_options {
+ liq_attr *liq;
+ liq_image *fixed_palette_image;
+ liq_log_callback_function *log_callback;
+ void *log_callback_user_info;
+ float floyd;
+ bool using_stdin, using_stdout, force, fast_compression, ie_mode,
+ min_quality_limit, skip_if_larger,
+ verbose;
+};
+
+pngquant_error prepare_output_image(liq_result *result, liq_image *input_image, png8_image *output_image);
+void set_palette(liq_result *result, png8_image *output_image);
+pngquant_error read_image(liq_attr *options, const char *filename, int using_stdin, png24_image *input_image_p, liq_image **liq_image_p, bool keep_input_pixels, bool verbose);
+pngquant_error write_image(png8_image *output_image, png24_image *output_image24, const char *outname, struct pngquant_options *options);
+char *add_filename_extension(const char *filename, const char *newext);
+
+void verbose_printf(struct pngquant_options *context, const char *fmt, ...);
+pngquant_error pngquant_file(const char *filename, const char *outname, struct pngquant_options *options);
+
diff --git a/src/drivers/libimagequant/rwpng.c b/src/drivers/libimagequant/rwpng.c
new file mode 100644
index 0000000..4c095ff
--- /dev/null
+++ b/src/drivers/libimagequant/rwpng.c
@@ -0,0 +1,615 @@
+/*---------------------------------------------------------------------------
+
+ pngquant: RGBA -> RGBA-palette quantization program rwpng.c
+
+ ---------------------------------------------------------------------------
+
+ © 1998-2000 by Greg Roelofs.
+ © 2009-2014 by Kornel Lesiński.
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "png.h"
+#include "rwpng.h"
+#if USE_LCMS
+#include "lcms2.h"
+#endif
+
+#ifndef Z_BEST_COMPRESSION
+#define Z_BEST_COMPRESSION 9
+#endif
+#ifndef Z_BEST_SPEED
+#define Z_BEST_SPEED 1
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#else
+#define omp_get_max_threads() 1
+#endif
+
+#if PNG_LIBPNG_VER < 10600
+//typedef png_const_charp png_const_bytep;
+#endif
+
+static void rwpng_error_handler(png_structp png_ptr, png_const_charp msg);
+static void rwpng_warning_stderr_handler(png_structp png_ptr, png_const_charp msg);
+static void rwpng_warning_silent_handler(png_structp png_ptr, png_const_charp msg);
+int rwpng_read_image24_cocoa(FILE *infile, png24_image *mainprog_ptr);
+
+
+void rwpng_version_info(FILE *fp)
+{
+ const char *pngver = png_get_header_ver(NULL);
+
+#if USE_COCOA
+ fprintf(fp, " Using Apple Cocoa image reader and libpng %s.\n", pngver);
+#elif USE_LCMS
+ fprintf(fp, " Using libpng %s with Little CMS color profile support.\n", pngver);
+#else
+ fprintf(fp, " Using libpng %s.\n", pngver);
+#endif
+
+#if PNG_LIBPNG_VER < 10600
+ if (strcmp(pngver, "1.3.") < 0) {
+ fputs("\nWARNING: Your version of libpng is outdated and may produce corrupted files.\n"
+ "Please recompile pngquant with the current version of libpng (1.6 or later).\n", fp);
+ } else if (strcmp(pngver, "1.6.") < 0) {
+ #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ fputs("\nWARNING: Your version of libpng is old and has buggy support for custom chunks.\n"
+ "Please recompile pngquant with the current version of libpng (1.6 or later).\n", fp);
+ #endif
+ }
+#endif
+}
+
+
+struct rwpng_read_data {
+ FILE *const fp;
+ png_size_t bytes_read;
+};
+
+static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ struct rwpng_read_data *read_data = (struct rwpng_read_data *)png_get_io_ptr(png_ptr);
+
+ png_size_t read = fread(data, 1, length, read_data->fp);
+ if (!read) {
+ png_error(png_ptr, "Read error");
+ }
+ read_data->bytes_read += read;
+}
+
+struct rwpng_write_state {
+ FILE *outfile;
+ png_size_t maximum_file_size;
+ png_size_t bytes_written;
+ pngquant_error retval;
+};
+
+static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ struct rwpng_write_state *write_state = (struct rwpng_write_state *)png_get_io_ptr(png_ptr);
+
+ if (SUCCESS != write_state->retval) {
+ return;
+ }
+
+ if (write_state->maximum_file_size && write_state->bytes_written + length > write_state->maximum_file_size) {
+ write_state->retval = TOO_LARGE_FILE;
+ }
+
+ if (!fwrite(data, 1, length, write_state->outfile)) {
+ write_state->retval = CANT_WRITE_ERROR;
+ }
+
+ write_state->bytes_written += length;
+}
+
+static void user_flush_data(png_structp png_ptr)
+{
+ // libpng never calls this :(
+}
+
+
+static png_bytepp rwpng_create_row_pointers(png_infop info_ptr, png_structp png_ptr, unsigned char *base, unsigned int height, unsigned int rowbytes)
+{
+ if (!rowbytes) {
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ }
+
+ png_bytepp row_pointers = malloc(height * sizeof(row_pointers[0]));
+ if (!row_pointers) return NULL;
+ for(unsigned int row = 0; row < height; ++row) {
+ row_pointers[row] = base + row * rowbytes;
+ }
+ return row_pointers;
+}
+
+static int read_chunk_callback(png_structp png_ptr, png_unknown_chunkp in_chunk)
+{
+ if (0 == memcmp("iCCP", in_chunk->name, 5) ||
+ 0 == memcmp("cHRM", in_chunk->name, 5) ||
+ 0 == memcmp("gAMA", in_chunk->name, 5)) {
+ return 0; // not handled
+ }
+
+ struct rwpng_chunk **head = (struct rwpng_chunk **)png_get_user_chunk_ptr(png_ptr);
+
+ struct rwpng_chunk *chunk = malloc(sizeof(struct rwpng_chunk));
+ memcpy(chunk->name, in_chunk->name, 5);
+ chunk->size = in_chunk->size;
+ chunk->location = in_chunk->location;
+ chunk->data = in_chunk->size ? malloc(in_chunk->size) : NULL;
+ if (in_chunk->size) {
+ memcpy(chunk->data, in_chunk->data, in_chunk->size);
+ }
+
+ chunk->next = *head;
+ *head = chunk;
+
+ return 1; // marks as "handled", libpng won't store it
+}
+
+/*
+ retval:
+ 0 = success
+ 21 = bad sig
+ 22 = bad IHDR
+ 24 = insufficient memory
+ 25 = libpng error (via longjmp())
+ 26 = wrong PNG color type (no alpha channel)
+ */
+
+pngquant_error rwpng_read_image24_libpng(FILE *infile, png24_image *mainprog_ptr, int verbose)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_size_t rowbytes;
+ int color_type, bit_depth;
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
+ rwpng_error_handler, verbose ? rwpng_warning_stderr_handler : rwpng_warning_silent_handler);
+ if (!png_ptr) {
+ return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return PNG_OUT_OF_MEMORY_ERROR; /* out of memory */
+ }
+
+ /* setjmp() must be called in every function that calls a non-trivial
+ * libpng function */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return LIBPNG_FATAL_ERROR; /* fatal libpng error (via longjmp()) */
+ }
+
+#if PNG_LIBPNG_VER >= 10500 && defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ /* copy standard chunks too */
+ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, (png_const_bytep)"pHYs\0iTXt\0tEXt\0zTXt", 4);
+#endif
+ png_set_read_user_chunk_fn(png_ptr, &mainprog_ptr->chunks, read_chunk_callback);
+
+ struct rwpng_read_data read_data = {infile, 0};
+ png_set_read_fn(png_ptr, &read_data, user_read_data);
+
+ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
+
+
+ /* alternatively, could make separate calls to png_get_image_width(),
+ * etc., but want bit_depth and color_type for later [don't care about
+ * compression_type and filter_type => NULLs] */
+
+ png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height,
+ &bit_depth, &color_type, NULL, NULL, NULL);
+
+
+ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
+ * transparency chunks to full alpha channel; strip 16-bit-per-sample
+ * images to 8 bits per sample; and convert grayscale to RGB[A] */
+
+ /* GRR TO DO: preserve all safe-to-copy ancillary PNG chunks */
+
+ if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
+#ifdef PNG_READ_FILLER_SUPPORTED
+ png_set_expand(png_ptr);
+ png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER);
+#else
+ fprintf(stderr, "pngquant readpng: image is neither RGBA nor GA\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ mainprog_ptr->retval = 26;
+ return mainprog_ptr->retval;
+#endif
+ }
+
+ if (bit_depth == 16) {
+ png_set_strip_16(png_ptr);
+ }
+
+ if (!(color_type & PNG_COLOR_MASK_COLOR)) {
+ png_set_gray_to_rgb(png_ptr);
+ }
+
+
+ /* get source gamma for gamma correction, or use sRGB default */
+ double gamma = 0.45455;
+ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ if (gamma < 0 || gamma > 1.0) {
+ fprintf(stderr, "pngquant readpng: ignored out-of-range gamma %f\n", gamma);
+ gamma = 0.45455;
+ }
+ }
+ mainprog_ptr->gamma = gamma;
+
+ png_set_interlace_handling(png_ptr);
+
+ /* all transformations have been registered; now update info_ptr data,
+ * get rowbytes and channels, and allocate image memory */
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+ if ((mainprog_ptr->rgba_data = malloc(rowbytes*mainprog_ptr->height)) == NULL) {
+ fprintf(stderr, "pngquant readpng: unable to allocate image data\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return PNG_OUT_OF_MEMORY_ERROR;
+ }
+
+ png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0);
+
+ /* now we can go ahead and just read the whole image */
+
+ png_read_image(png_ptr, row_pointers);
+
+ /* and we're done! (png_read_end() can be omitted if no processing of
+ * post-IDAT text/time/etc. is desired) */
+
+ png_read_end(png_ptr, NULL);
+
+#if USE_LCMS
+#if PNG_LIBPNG_VER < 10500
+ png_charp ProfileData;
+#else
+ png_bytep ProfileData;
+#endif
+ png_uint_32 ProfileLen;
+
+ cmsHPROFILE hInProfile = NULL;
+
+ /* color_type is read from the image before conversion to RGBA */
+ int COLOR_PNG = color_type & PNG_COLOR_MASK_COLOR;
+
+ mainprog_ptr->lcms_status = NONE;
+
+ /* embedded ICC profile */
+ if (png_get_iCCP(png_ptr, info_ptr, &(png_charp){0}, &(int){0}, &ProfileData, &ProfileLen)) {
+
+ hInProfile = cmsOpenProfileFromMem(ProfileData, ProfileLen);
+ cmsColorSpaceSignature colorspace = cmsGetColorSpace(hInProfile);
+
+ /* only RGB (and GRAY) valid for PNGs */
+ if (colorspace == cmsSigRgbData && COLOR_PNG) {
+ mainprog_ptr->lcms_status = ICCP;
+ } else {
+ if (colorspace == cmsSigGrayData && !COLOR_PNG) {
+ mainprog_ptr->lcms_status = ICCP_WARN_GRAY;
+ }
+ cmsCloseProfile(hInProfile);
+ hInProfile = NULL;
+ }
+ }
+
+ /* build RGB profile from cHRM and gAMA */
+ if (hInProfile == NULL && COLOR_PNG &&
+ !png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB) &&
+ png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) &&
+ png_get_valid(png_ptr, info_ptr, PNG_INFO_cHRM)) {
+
+ cmsCIExyY WhitePoint;
+ cmsCIExyYTRIPLE Primaries;
+
+ png_get_cHRM(png_ptr, info_ptr, &WhitePoint.x, &WhitePoint.y,
+ &Primaries.Red.x, &Primaries.Red.y,
+ &Primaries.Green.x, &Primaries.Green.y,
+ &Primaries.Blue.x, &Primaries.Blue.y);
+
+ WhitePoint.Y = Primaries.Red.Y = Primaries.Green.Y = Primaries.Blue.Y = 1.0;
+
+ cmsToneCurve *GammaTable[3];
+ GammaTable[0] = GammaTable[1] = GammaTable[2] = cmsBuildGamma(NULL, 1/gamma);
+
+ hInProfile = cmsCreateRGBProfile(&WhitePoint, &Primaries, GammaTable);
+
+ cmsFreeToneCurve(GammaTable[0]);
+
+ mainprog_ptr->lcms_status = GAMA_CHRM;
+ }
+
+ /* transform image to sRGB colorspace */
+ if (hInProfile != NULL) {
+
+ cmsHPROFILE hOutProfile = cmsCreate_sRGBProfile();
+ cmsHTRANSFORM hTransform = cmsCreateTransform(hInProfile, TYPE_RGBA_8,
+ hOutProfile, TYPE_RGBA_8,
+ INTENT_PERCEPTUAL,
+ omp_get_max_threads() > 1 ? cmsFLAGS_NOCACHE : 0);
+
+ #pragma omp parallel for \
+ if (mainprog_ptr->height*mainprog_ptr->width > 8000) \
+ schedule(static)
+ for (unsigned int i = 0; i < mainprog_ptr->height; i++) {
+ /* It is safe to use the same block for input and output,
+ when both are of the same TYPE. */
+ cmsDoTransform(hTransform, row_pointers[i],
+ row_pointers[i],
+ mainprog_ptr->width);
+ }
+
+ cmsDeleteTransform(hTransform);
+ cmsCloseProfile(hOutProfile);
+ cmsCloseProfile(hInProfile);
+
+ mainprog_ptr->gamma = 0.45455;
+ }
+#endif
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ mainprog_ptr->file_size = read_data.bytes_read;
+ mainprog_ptr->row_pointers = (unsigned char **)row_pointers;
+
+ return SUCCESS;
+}
+
+static void rwpng_free_chunks(struct rwpng_chunk *chunk) {
+ if (!chunk) return;
+ rwpng_free_chunks(chunk->next);
+ free(chunk->data);
+ free(chunk);
+}
+
+void rwpng_free_image24(png24_image *image)
+{
+ free(image->row_pointers);
+ image->row_pointers = NULL;
+
+ free(image->rgba_data);
+ image->rgba_data = NULL;
+
+ rwpng_free_chunks(image->chunks);
+ image->chunks = NULL;
+}
+
+void rwpng_free_image8(png8_image *image)
+{
+ free(image->indexed_data);
+ image->indexed_data = NULL;
+
+ free(image->row_pointers);
+ image->row_pointers = NULL;
+
+ rwpng_free_chunks(image->chunks);
+ image->chunks = NULL;
+}
+
+pngquant_error rwpng_read_image24(FILE *infile, png24_image *input_image_p, int verbose)
+{
+#if USE_COCOA
+ return rwpng_read_image24_cocoa(infile, input_image_p);
+#else
+ return rwpng_read_image24_libpng(infile, input_image_p, verbose);
+#endif
+}
+
+
+static pngquant_error rwpng_write_image_init(rwpng_png_image *mainprog_ptr, png_structpp png_ptr_p, png_infopp info_ptr_p, int fast_compression)
+{
+ /* could also replace libpng warning-handler (final NULL), but no need: */
+
+ *png_ptr_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, rwpng_error_handler, NULL);
+
+ if (!(*png_ptr_p)) {
+ return LIBPNG_INIT_ERROR; /* out of memory */
+ }
+
+ *info_ptr_p = png_create_info_struct(*png_ptr_p);
+ if (!(*info_ptr_p)) {
+ png_destroy_write_struct(png_ptr_p, NULL);
+ return LIBPNG_INIT_ERROR; /* out of memory */
+ }
+
+ /* setjmp() must be called in every function that calls a PNG-writing
+ * libpng function, unless an alternate error handler was installed--
+ * but compatible error handlers must either use longjmp() themselves
+ * (as in this program) or exit immediately, so here we go: */
+
+ if (setjmp(mainprog_ptr->jmpbuf)) {
+ png_destroy_write_struct(png_ptr_p, info_ptr_p);
+ return LIBPNG_INIT_ERROR; /* libpng error (via longjmp()) */
+ }
+
+ png_set_compression_level(*png_ptr_p, fast_compression ? Z_BEST_SPEED : Z_BEST_COMPRESSION);
+ png_set_compression_mem_level(*png_ptr_p, fast_compression ? 9 : 5); // judging by optipng results, smaller mem makes libpng compress slightly better
+
+ return SUCCESS;
+}
+
+
+void rwpng_write_end(png_infopp info_ptr_p, png_structpp png_ptr_p, png_bytepp row_pointers)
+{
+ png_write_info(*png_ptr_p, *info_ptr_p);
+
+ png_set_packing(*png_ptr_p);
+
+ png_write_image(*png_ptr_p, row_pointers);
+
+ png_write_end(*png_ptr_p, NULL);
+
+ png_destroy_write_struct(png_ptr_p, info_ptr_p);
+}
+
+void rwpng_set_gamma(png_infop info_ptr, png_structp png_ptr, double gamma)
+{
+ /* remap sets gamma to 0.45455 */
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ png_set_sRGB(png_ptr, info_ptr, 0); // 0 = Perceptual
+}
+
+pngquant_error rwpng_write_image8(FILE *outfile, const png8_image *mainprog_ptr)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ pngquant_error retval = rwpng_write_image_init((rwpng_png_image*)mainprog_ptr, &png_ptr, &info_ptr, mainprog_ptr->fast_compression);
+ if (retval) return retval;
+
+ struct rwpng_write_state write_state;
+ write_state = (struct rwpng_write_state){
+ .outfile = outfile,
+ .maximum_file_size = mainprog_ptr->maximum_file_size,
+ .retval = SUCCESS,
+ };
+ png_set_write_fn(png_ptr, &write_state, user_write_data, user_flush_data);
+
+ // Palette images generally don't gain anything from filtering
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_VALUE_NONE);
+
+ rwpng_set_gamma(info_ptr, png_ptr, mainprog_ptr->gamma);
+
+ /* set the image parameters appropriately */
+ int sample_depth;
+#if PNG_LIBPNG_VER > 10400 /* old libpng corrupts files with low depth */
+ if (mainprog_ptr->num_palette <= 2)
+ sample_depth = 1;
+ else if (mainprog_ptr->num_palette <= 4)
+ sample_depth = 2;
+ else if (mainprog_ptr->num_palette <= 16)
+ sample_depth = 4;
+ else
+#endif
+ sample_depth = 8;
+
+ struct rwpng_chunk *chunk = mainprog_ptr->chunks;
+ int chunk_num=0;
+ while(chunk) {
+ png_unknown_chunk pngchunk = {
+ .size = chunk->size,
+ .data = chunk->data,
+ .location = chunk->location,
+ };
+ memcpy(pngchunk.name, chunk->name, 5);
+ png_set_unknown_chunks(png_ptr, info_ptr, &pngchunk, 1);
+
+ #if defined(PNG_HAVE_IHDR) && PNG_LIBPNG_VER < 10600
+ png_set_unknown_chunk_location(png_ptr, info_ptr, chunk_num, pngchunk.location ? pngchunk.location : PNG_HAVE_IHDR);
+ #endif
+
+ chunk = chunk->next;
+ chunk_num++;
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
+ sample_depth, PNG_COLOR_TYPE_PALETTE,
+ 0, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_BASE);
+
+ png_set_PLTE(png_ptr, info_ptr, &mainprog_ptr->palette[0], mainprog_ptr->num_palette);
+
+ if (mainprog_ptr->num_trans > 0) {
+ png_set_tRNS(png_ptr, info_ptr, mainprog_ptr->trans, mainprog_ptr->num_trans, NULL);
+ }
+
+ rwpng_write_end(&info_ptr, &png_ptr, mainprog_ptr->row_pointers);
+
+ return write_state.retval;
+}
+
+pngquant_error rwpng_write_image24(FILE *outfile, const png24_image *mainprog_ptr)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ pngquant_error retval = rwpng_write_image_init((rwpng_png_image*)mainprog_ptr, &png_ptr, &info_ptr, 0);
+ if (retval) return retval;
+
+ png_init_io(png_ptr, outfile);
+
+ rwpng_set_gamma(info_ptr, png_ptr, mainprog_ptr->gamma);
+
+ png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
+ 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ 0, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_BASE);
+
+
+ png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0);
+
+ rwpng_write_end(&info_ptr, &png_ptr, row_pointers);
+
+ free(row_pointers);
+
+ return SUCCESS;
+}
+
+
+static void rwpng_warning_stderr_handler(png_structp png_ptr, png_const_charp msg) {
+ fprintf(stderr, " %s\n", msg);
+}
+
+static void rwpng_warning_silent_handler(png_structp png_ptr, png_const_charp msg) {
+}
+
+static void rwpng_error_handler(png_structp png_ptr, png_const_charp msg)
+{
+ rwpng_png_image *mainprog_ptr;
+
+ /* This function, aside from the extra step of retrieving the "error
+ * pointer" (below) and the fact that it exists within the application
+ * rather than within libpng, is essentially identical to libpng's
+ * default error handler. The second point is critical: since both
+ * setjmp() and longjmp() are called from the same code, they are
+ * guaranteed to have compatible notions of how big a jmp_buf is,
+ * regardless of whether _BSD_SOURCE or anything else has (or has not)
+ * been defined. */
+
+ fprintf(stderr, " error: %s\n", msg);
+ fflush(stderr);
+
+ mainprog_ptr = png_get_error_ptr(png_ptr);
+ if (mainprog_ptr == NULL) abort();
+
+ longjmp(mainprog_ptr->jmpbuf, 1);
+}
diff --git a/src/drivers/libimagequant/rwpng.h b/src/drivers/libimagequant/rwpng.h
new file mode 100644
index 0000000..28daf7c
--- /dev/null
+++ b/src/drivers/libimagequant/rwpng.h
@@ -0,0 +1,124 @@
+/*---------------------------------------------------------------------------
+
+ pngquant: RGBA -> RGBA-palette quantization program rwpng.h
+
+ ---------------------------------------------------------------------------
+
+ © 1998-2000 by Greg Roelofs.
+ © 2009-2014 by Kornel Lesiński.
+
+ 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef RWPNG_H
+#define RWPNG_H
+
+#include "png.h" /* if this include fails, you need to install libpng (e.g. libpng-devel package) and run ./configure */
+#include <setjmp.h>
+
+#ifndef USE_COCOA
+#define USE_COCOA 0
+#endif
+
+typedef enum {
+ SUCCESS = 0,
+ MISSING_ARGUMENT = 1,
+ READ_ERROR = 2,
+ INVALID_ARGUMENT = 4,
+ NOT_OVERWRITING_ERROR = 15,
+ CANT_WRITE_ERROR = 16,
+ OUT_OF_MEMORY_ERROR = 17,
+ WRONG_ARCHITECTURE = 18, // Missing SSE
+ PNG_OUT_OF_MEMORY_ERROR = 24,
+ LIBPNG_FATAL_ERROR = 25,
+ LIBPNG_INIT_ERROR = 35,
+ TOO_LARGE_FILE = 98,
+ TOO_LOW_QUALITY = 99,
+} pngquant_error;
+
+struct rwpng_chunk {
+ struct rwpng_chunk *next;
+ png_byte *data;
+ png_size_t size;
+ png_byte name[5];
+ png_byte location;
+};
+
+#if USE_LCMS
+typedef enum {
+ NONE = 0,
+ ICCP = 1, // used ICC profile
+ ICCP_WARN_GRAY = 2, // ignore and warn about GRAY ICC profile
+ GAMA_CHRM = 3, // used gAMA and cHARM
+} lcms_transform;
+#endif
+
+typedef struct {
+ jmp_buf jmpbuf;
+ png_uint_32 width;
+ png_uint_32 height;
+ png_size_t file_size;
+ double gamma;
+ unsigned char **row_pointers;
+ unsigned char *rgba_data;
+ struct rwpng_chunk *chunks;
+#if USE_LCMS
+ lcms_transform lcms_status;
+#endif
+} png24_image;
+
+typedef struct {
+ jmp_buf jmpbuf;
+ png_uint_32 width;
+ png_uint_32 height;
+ png_size_t maximum_file_size;
+ double gamma;
+ unsigned char **row_pointers;
+ unsigned char *indexed_data;
+ unsigned int num_palette;
+ unsigned int num_trans;
+ png_color palette[256];
+ unsigned char trans[256];
+ struct rwpng_chunk *chunks;
+ char fast_compression;
+} png8_image;
+
+typedef union {
+ jmp_buf jmpbuf;
+ png24_image png24;
+ png8_image png8;
+} rwpng_png_image;
+
+/* prototypes for public functions in rwpng.c */
+
+void rwpng_version_info(FILE *fp);
+
+pngquant_error rwpng_read_image24(FILE *infile, png24_image *mainprog_ptr, int verbose);
+pngquant_error rwpng_write_image8(FILE *outfile, const png8_image *mainprog_ptr);
+pngquant_error rwpng_write_image24(FILE *outfile, const png24_image *mainprog_ptr);
+void rwpng_free_image24(png24_image *);
+void rwpng_free_image8(png8_image *);
+
+#endif
diff --git a/src/drivers/libimagequant/viter.c b/src/drivers/libimagequant/viter.c
new file mode 100644
index 0000000..109a165
--- /dev/null
+++ b/src/drivers/libimagequant/viter.c
@@ -0,0 +1,89 @@
+
+#include "libimagequant.h"
+#include "pam.h"
+#include "viter.h"
+#include "nearest.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _OPENMP
+#include <omp.h>
+#else
+#define omp_get_max_threads() 1
+#define omp_get_thread_num() 0
+#endif
+
+/*
+ * Voronoi iteration: new palette color is computed from weighted average of colors that map to that palette entry.
+ */
+LIQ_PRIVATE void viter_init(const colormap *map, const unsigned int max_threads, viter_state average_color[])
+{
+ memset(average_color, 0, sizeof(average_color[0])*(VITER_CACHE_LINE_GAP+map->colors)*max_threads);
+}
+
+LIQ_PRIVATE void viter_update_color(const f_pixel acolor, const float value, const colormap *map, unsigned int match, const unsigned int thread, viter_state average_color[])
+{
+ match += thread * (VITER_CACHE_LINE_GAP+map->colors);
+ average_color[match].a += acolor.a * value;
+ average_color[match].r += acolor.r * value;
+ average_color[match].g += acolor.g * value;
+ average_color[match].b += acolor.b * value;
+ average_color[match].total += value;
+}
+
+LIQ_PRIVATE void viter_finalize(colormap *map, const unsigned int max_threads, const viter_state average_color[])
+{
+ for (unsigned int i=0; i < map->colors; i++) {
+ double a=0, r=0, g=0, b=0, total=0;
+
+ // Aggregate results from all threads
+ for(unsigned int t=0; t < max_threads; t++) {
+ const unsigned int offset = (VITER_CACHE_LINE_GAP+map->colors) * t + i;
+
+ a += average_color[offset].a;
+ r += average_color[offset].r;
+ g += average_color[offset].g;
+ b += average_color[offset].b;
+ total += average_color[offset].total;
+ }
+
+ if (total) {
+ map->palette[i].acolor = (f_pixel){
+ .a = a / total,
+ .r = r / total,
+ .g = g / total,
+ .b = b / total,
+ };
+ }
+ map->palette[i].popularity = total;
+ }
+}
+
+LIQ_PRIVATE double viter_do_iteration(histogram *hist, colormap *const map, const float min_opaque_val, viter_callback callback, const bool fast_palette)
+{
+ const unsigned int max_threads = omp_get_max_threads();
+ viter_state average_color[(VITER_CACHE_LINE_GAP+map->colors) * max_threads];
+ viter_init(map, max_threads, average_color);
+ struct nearest_map *const n = nearest_init(map, fast_palette);
+ hist_item *const achv = hist->achv;
+ const int hist_size = hist->size;
+
+ double total_diff=0;
+ #pragma omp parallel for if (hist_size > 3000) \
+ schedule(static) default(none) shared(average_color,callback) reduction(+:total_diff)
+ for(int j=0; j < hist_size; j++) {
+ float diff;
+ unsigned int match = nearest_search(n, achv[j].acolor, achv[j].tmp.likely_colormap_index, min_opaque_val, &diff);
+ achv[j].tmp.likely_colormap_index = match;
+ total_diff += diff * achv[j].perceptual_weight;
+
+ viter_update_color(achv[j].acolor, achv[j].perceptual_weight, map, match, omp_get_thread_num(), average_color);
+
+ if (callback) callback(&achv[j], diff);
+ }
+
+ nearest_free(n);
+ viter_finalize(map, max_threads, average_color);
+
+ return total_diff / hist->total_perceptual_weight;
+}
diff --git a/src/drivers/libimagequant/viter.h b/src/drivers/libimagequant/viter.h
new file mode 100644
index 0000000..c1a5b39
--- /dev/null
+++ b/src/drivers/libimagequant/viter.h
@@ -0,0 +1,19 @@
+
+#ifndef VITER_H
+#define VITER_H
+
+// Spread memory touched by different threads at least 64B apart which I assume is the cache line size. This should avoid memory write contention.
+#define VITER_CACHE_LINE_GAP ((64+sizeof(viter_state)-1)/sizeof(viter_state))
+
+typedef struct {
+ double a, r, g, b, total;
+} viter_state;
+
+typedef void (*viter_callback)(hist_item *item, float diff);
+
+LIQ_PRIVATE void viter_init(const colormap *map, const unsigned int max_threads, viter_state state[]);
+LIQ_PRIVATE void viter_update_color(const f_pixel acolor, const float value, const colormap *map, unsigned int match, const unsigned int thread, viter_state average_color[]);
+LIQ_PRIVATE void viter_finalize(colormap *map, const unsigned int max_threads, const viter_state state[]);
+LIQ_PRIVATE double viter_do_iteration(histogram *hist, colormap *const map, const float min_opaque_val, viter_callback callback, const bool fast_palette);
+
+#endif
diff --git a/src/drivers/minizip/zip.c b/src/drivers/minizip/zip.c
index 8b75d7c..5529fbb 100644
--- a/src/drivers/minizip/zip.c
+++ b/src/drivers/minizip/zip.c
@@ -758,9 +758,9 @@ extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
zi->ci.flag = 0;
if ((level==8) || (level==9))
zi->ci.flag |= 2;
- if ((level==2))
+ if (level==2)
zi->ci.flag |= 4;
- if ((level==1))
+ if (level==1)
zi->ci.flag |= 6;
if (password != NULL)
zi->ci.flag |= 1;
diff --git a/src/eckit_readers/CMakeLists.txt b/src/eckit_readers/CMakeLists.txt
index 79f2703..9c56172 100644
--- a/src/eckit_readers/CMakeLists.txt
+++ b/src/eckit_readers/CMakeLists.txt
@@ -5,7 +5,7 @@ set( _eckit_srcs
-if ( MAGICS_BUFR )
+if ( HAVE_BUFR )
list (APPEND _eckit_srcs
MvLocation.cc
MvObsSet.cc
diff --git a/src/eckit_readers/TableReader.cc b/src/eckit_readers/TableReader.cc
index a3c5fd7..c590876 100644
--- a/src/eckit_readers/TableReader.cc
+++ b/src/eckit_readers/TableReader.cc
@@ -368,7 +368,7 @@ bool TableReader::readUserMetaData (char *line, size_t sizeOfLine, string &error
if (tokens2.size() != 2) // should only be 2 tokens: PARAM and VALUE
{
char msg [2000];
- sprintf (msg, "Error parsing parameter %d: '%s'", j+1, tokens[j]);
+ sprintf (msg, "Error parsing parameter %lu: '%s'", j+1, tokens[j]);
errorMessage = msg;
return false;
}
diff --git a/src/libMagWrapper/MagPlus.cc b/src/libMagWrapper/MagPlus.cc
index 149b1c2..14d7e7d 100644
--- a/src/libMagWrapper/MagPlus.cc
+++ b/src/libMagWrapper/MagPlus.cc
@@ -12,24 +12,24 @@
#include "MetaDataWrapper.h"
#include "ImportObjectHandlerWrapper.h"
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
#include <GribDecoderWrapper.h>
#include <GribLoopWrapper.h>
#endif
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
#include <NetcdfDecoderWrapper.h>
#endif
#include <GeoPointsDecoderWrapper.h>
#include <BinningObjectWrapper.h>
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
#include <OdaGeoDecoderWrapper.h>
#include <OdaXYDecoderWrapper.h>
#endif
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
#include <ObsDecoderWrapper.h>
#include <ObsPlottingWrapper.h>
#endif
@@ -38,7 +38,7 @@
#include <ImportActionWrapper.h>
#include <InputDataWrapper.h>
#include <TableDecoderWrapper.h>
-
+#include <GeoJSonWrapper.h>
#include <ContourWrapper.h>
#include <TextVisitor.h>
@@ -52,16 +52,17 @@
#include <UserPoint.h>
#include "MagicsEvent.h"
-
+#include "MagJSon.h"
#include <PostScriptDriverWrapper.h>
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
#include <CairoDriverWrapper.h>
#endif
#include <SVGDriverWrapper.h>
#include <KMLDriverWrapper.h>
+#include <GeoJsonDriverWrapper.h>
#ifdef MAGICS_QT
#include <QtDriver.h>
@@ -76,9 +77,9 @@ void replace(magics::MagRequest& request, const string& name, T from, T to)
return;
}
T val = request(name);
- if (val == from)
+ if (val == from)
request(name) = to;
-
+
}
void replace_string(magics::MagRequest& request, const string& name, const string& from, const string& to)
@@ -88,9 +89,9 @@ void replace_string(magics::MagRequest& request, const string& name, const strin
return;
}
string val = request(name);
- if (val == from)
+ if (val == from)
request(name) = to;
-
+
}
template <class T>
@@ -101,19 +102,19 @@ void replace(magics::MagRequest& request, const string& name, T from, const stri
return;
}
T val = request(name);
- if (val == from)
+ if (val == from)
request(newname) = to;
- else
+ else
request(newname) = val;
}
string get(magics::MagRequest& request, const string& param, const string& val)
{
-
+
string v = request(param);
-
- return ( !v.empty() ) ? v : val;
-}
+
+ return ( !v.empty() ) ? v : val;
+}
using namespace std;
using namespace magics;
@@ -139,7 +140,7 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
}
if ( dataCreators_.empty()) {
dataCreators_["GEOPOINTS"] = &MagPlus::createGeopoints;
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
dataCreators_["NETCDF_GEOPOINTS"] = &MagPlus::createnetcdf;
dataCreators_["NETCDF_GEOVECTORS"] = &MagPlus::createnetcdf;
dataCreators_["NETCDF_GEOMATRIX"] = &MagPlus::createnetcdf;
@@ -154,7 +155,7 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
dataCreators_["NETCDF_XY_MATRIX"] = &MagPlus::createnetcdf;
#endif
}
- if ( sceneCreators_.empty()) {
+ if ( sceneCreators_.empty()) {
sceneCreators_["PAGE"] = &MagPlus::page;
sceneCreators_["NEWPAGE"] = &MagPlus::newpage;
sceneCreators_["MCOAST"] = &MagPlus::coastlines;
@@ -165,10 +166,11 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
sceneCreators_["PAXIS"] = &MagPlus::axis;
sceneCreators_["CARTESIANVIEW"] = &MagPlus::cartesian;
sceneCreators_["PGRIB"] = &MagPlus::gribloop;
+ sceneCreators_["GEOJSON"] = &MagPlus::geojson;
sceneCreators_["GRIBLOOP"] = &MagPlus::gribloop;
sceneCreators_["DATALOOP"] = &MagPlus::dataloop;
sceneCreators_["GEOPOINTS"] = &MagPlus::geopoints;
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
sceneCreators_["NETCDF_GEOPOINTS"] = &MagPlus::netcdf;
sceneCreators_["NETCDF_GEOVECTORS"] = &MagPlus::netcdf;
sceneCreators_["NETCDF_GEOMATRIX"] = &MagPlus::netcdf;
@@ -199,7 +201,7 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
sceneCreators_["cartesian"] = &MagPlus::cartesianGrid;
sceneCreators_["tephigram"] = &MagPlus::tephiGrid;
sceneCreators_["taylor"] = &MagPlus::taylorGrid;
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
sceneCreators_["ODB_GEO_POINTS"] = &MagPlus::geoodb;
sceneCreators_["ODB_GEO_VECTORS"] = &MagPlus::geoodb;
sceneCreators_["ODB_XY_POINTS"] = &MagPlus::xyodb;
@@ -228,7 +230,7 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
sceneCreators_["PRASTERLOOP"] = &MagPlus::rasterloop;
sceneCreators_["BINNING_OBJECT"] = &MagPlus::binning;
}
-
+
if ( driverCreators_.empty())
{
#ifdef MAGICS_QT
@@ -237,6 +239,7 @@ MagPlus::MagPlus() : root_(0), superpage_(-1), geographical_(true), mode_(intera
driverCreators_["PSOUTPUT"] = &MagPlus::psdriver;
driverCreators_["PNGOUTPUT"] = &MagPlus::pngdriver;
driverCreators_["KMLOUTPUT"] = &MagPlus::kmldriver;
+ driverCreators_["GEOJSONOUTPUT"] = &MagPlus::geojsondriver;
driverCreators_["PDFOUTPUT"] = &MagPlus::pdfdriver;
driverCreators_["SVGOUTPUT"] = &MagPlus::svgdriver;
driverCreators_["EPSOUTPUT"] = &MagPlus::epsdriver;
@@ -257,15 +260,15 @@ bool MagPlus::superpage(magics::MagRequest& in)
if ( superpage == superpage_) return false;
superpage_ = superpage;
in("LAYOUT") = "positional";
-
+
replace_string(in, "SUPER_PAGE_FRAME_COLOUR", "BLUE", "grey");
-
+
in.print();
MvRootSceneNodeWrapper helper;
helper.set(in);
-
+
root_ = helper.object();
-
+
MagLog::dev()<< "<----superpage" << endl;
return false;
}
@@ -283,9 +286,9 @@ bool MagPlus::newpage(magics::MagRequest& in)
bool MagPlus::psdriver(magics::MagRequest& in)
{
PostScriptDriverWrapper helper;
- helper.set(in);
-
- drivers_.push_back(helper.object());
+ helper.set(in);
+
+ drivers_.push_back(helper.object());
mode_ = paper;
return false;
}
@@ -293,20 +296,20 @@ bool MagPlus::psdriver(magics::MagRequest& in)
bool MagPlus::epsdriver(magics::MagRequest& in)
{
PostScriptDriverWrapper helper;
- helper.set(in);
+ helper.set(in);
helper.me()->setEPS(true);
- drivers_.push_back(helper.object());
+ drivers_.push_back(helper.object());
mode_ = paper;
return false;
}
bool MagPlus::pngdriver(magics::MagRequest& in)
{
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
CairoDriverWrapper helper;
- helper.set(in);
+ helper.set(in);
helper.me()->setPNG();
- drivers_.push_back(helper.object());
+ drivers_.push_back(helper.object());
mode_ = paper;
#endif
return false;
@@ -314,13 +317,13 @@ bool MagPlus::pngdriver(magics::MagRequest& in)
bool MagPlus::pdfdriver(magics::MagRequest& in)
{
-#ifdef MAGICS_CAIRO
+#ifdef HAVE_CAIRO
CairoDriverWrapper helper;
- helper.set(in);
+ helper.set(in);
helper.me()->setPDF();
- drivers_.push_back(helper.object());
+ drivers_.push_back(helper.object());
mode_ = paper;
-
+
#endif
return false;
}
@@ -335,13 +338,13 @@ bool MagPlus::qtdriver(magics::MagRequest& /*in*/)
{
if ( !qtDriver_)
{
- assert(qtScene_);
+ ASSERT(qtScene_);
qtDriver_ = new magics::QtDriver();
qtDriver_->setScene(qtScene_);
}
#ifndef MAG_NEXT
- drivers_.push_back(qtDriver_);
+ drivers_.push_back(qtDriver_);
#else
if ( mvMode_ == creation )
drivers_.push_back(qtDriver_);
@@ -355,9 +358,9 @@ bool MagPlus::qtdriver(magics::MagRequest& /*in*/)
bool MagPlus::svgdriver(magics::MagRequest& in)
{
SVGDriverWrapper helper;
- helper.set(in);
+ helper.set(in);
- drivers_.push_back(helper.object());
+ drivers_.push_back(helper.object());
mode_ = paper;
return false;
}
@@ -366,9 +369,20 @@ bool MagPlus::kmldriver(magics::MagRequest& in)
{
KMLDriverWrapper helper;
in("KML_DESCRIPTION") = "Metview/Magics++";
- helper.set(in);
+ helper.set(in);
+ mode_ = paper;
+ drivers_.push_back(helper.object());
+
+ return false;
+}
+
+bool MagPlus::geojsondriver(magics::MagRequest& in)
+{
+ GeoJsonDriverWrapper helper;
+ in("GEOJSON_DESCRIPTION") = "Metview/Magics++";
+ helper.set(in);
mode_ = paper;
- drivers_.push_back(helper.object());
+ drivers_.push_back(helper.object());
return false;
}
@@ -427,7 +441,7 @@ bool MagPlus::page(magics::MagRequest& in)
pages_[i] = viewhelper;
if ( !id.empty() )
{
- view->setInteractiveInfo(id.c_str(),
+ view->setInteractiveInfo(id.c_str(),
in("ZOOM_NUMBER_OF_LEVELS"), in("ZOOM_CURRENT_LEVEL"));
}
top()->insert(view);
@@ -449,7 +463,7 @@ bool MagPlus::page(magics::MagRequest& in)
int id = in("METVIEW_ID");
pages_[id] = page_;
}
-
+
MagLog::dev()<< "<----page and subpage" << endl;
return false; // do not exit
}
@@ -468,11 +482,11 @@ bool MagPlus::cartesian(magics::MagRequest& in) {
if ( !id.empty() )
{
string id = in("METVIEW_ID");
- view->setInteractiveInfo(id.c_str(),
+ view->setInteractiveInfo(id.c_str(),
in("ZOOM_NUMBER_OF_LEVELS"), in("ZOOM_CURRENT_LEVEL"));
}
top()->insert(view);
- push(view);
+ push(view);
in.print();
@@ -574,7 +588,9 @@ bool MagPlus::cartesianGrid(magics::MagRequest& in) {
top()->push_back(vaxis);
}
+ return true; //< @note return value was missing, what should it return?
}
+
bool MagPlus::tephiGrid(magics::MagRequest& in)
{
magics::MagRequest& tephi = in.getSubRequest("THERMO_GRID");
@@ -596,6 +612,7 @@ bool MagPlus::tephiGrid(magics::MagRequest& in)
top()->push_back(grid);
}
+ return true; //< @note return value was missing, what should it return?
}
bool MagPlus::taylorGrid(magics::MagRequest& in)
{
@@ -617,28 +634,30 @@ bool MagPlus::taylorGrid(magics::MagRequest& in)
grid->icon("Taylor Grid", "MTAYLOR");
top()->push_back(grid);
}
+ return true; //< @note return value was missing, what should it return?
}
bool MagPlus::oldcoastlines(magics::MagRequest& in)
{
replace_string(in, "MAP_COASTLINE_RESOLUTION", "MEDIUM", "automatic");
coastlines(in);
+ return true; //< @note return value was missing, what should it return?
}
bool MagPlus::coastlines(magics::MagRequest& in)
{
MagLog::dev()<< "add coastlines" << endl;
-
+
replace_string(in, "_NAME", "", "Coastlines");
replace_string(in, "_CLASS", "", "MCOAST");
CoastlinesWrapper helper;
-
+
helper.set(in);
-
+
top()->push_back(helper.object());
setIconInfo(in,*helper.object());
MagLog::dev()<< top() << endl;
MagLog::dev()<< *helper.object() << endl;
-
+
return false; // do not exit
}
bool MagPlus::tephigrid(magics::MagRequest& in)
@@ -665,14 +684,14 @@ bool MagPlus::axis(magics::MagRequest& in)
MagLog::dev()<< "add axis" << endl;
string orientation = in("AXIS_ORIENTATION");
Axis* axis = 0;
- if ( magCompare(orientation, "vertical") )
+ if ( magCompare(orientation, "vertical") )
axis = new VerticalAxis();
- else
+ else
axis = new HorizontalAxis();
-
- AxisWrapper helper(axis);
+
+ AxisWrapper helper(axis);
helper.set(in);
-
+
top()->push_back(axis);
MagLog::dev() << *axis << "\n";
@@ -691,24 +710,24 @@ bool MagPlus::import(magics::MagRequest& in)
bool MagPlus::raster(magics::MagRequest& in)
{
MagLog::dev()<< "import a raster object" << endl;
-
+
in.print();
in("IMPORT_FILE_NAME") = in("IMPORT_FILE_PATH");
in("IMPORT_FORMAT") = in("IMPORT_FILE_TYPE");
-
+
ImportActionWrapper object;
ImportPlotWrapper visdef;
-
+
object.set(in);
visdef.set(in);
setIconInfo(in, *object.object());
setIconInfo(in, *visdef.object());
-
-
+
+
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
+ push(action);
top()->data(object.object());
top()->visdef(visdef.object());
pop();
@@ -729,14 +748,14 @@ bool MagPlus::binning(magics::MagRequest& in)
bool MagPlus::grib(magics::MagRequest& in)
{
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
MagLog::dev()<< "add grib" << endl;
in.print();
-
+
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
-
+ push(action);
+
GribDecoderWrapper grib;
grib.set(in);
setIconInfo(in, *grib.object());
@@ -752,29 +771,29 @@ bool MagPlus::table(magics::MagRequest& in)
MagLog::dev()<< "add table" << endl;
in.print();
- // First set the table_filename...
+ // First set the table_filename...
magics::MagRequest& data = in.getSubRequest("TABLE_DATA");
if(data)
- {
+ {
if(data.getVerb() == "TABLE" || data.getVerb() == "NOTE" || data.getVerb() == "GEOPOINTS")
{
string x = data("PATH");
in("TABLE_FILENAME") = x;
- }
-
- else if( data.getVerb() == "TABLE_READER" )
+ }
+
+ else if( data.getVerb() == "TABLE_READER" )
{
magics::MagRequest& d = data.getSubRequest("DATA");
- if (d)
+ if (d)
{
in("TABLE_FILENAME") = d("PATH");
}
- else
+ else
{
in("TABLE_FILENAME") = data("TABLE_FILENAME");
}
- }
+ }
}
if ( geographical_ ) {
@@ -890,40 +909,40 @@ bool MagPlus::input(magics::MagRequest& in)
return false; // do not exit
}
-void MagPlus::setIconInfo(magics::MagRequest& mv, MetviewIcon& object)
+void MagPlus::setIconInfo(magics::MagRequest& mv, MetviewIcon& object)
{
string iconname = get(mv, "_NAME", "");
string iconclass = get(mv, "_CLASS", "");
if(iconclass.empty())
- iconclass = get(mv, "_VERB", "");
+ iconclass = get(mv, "_VERB", "");
string iconid = get(mv, "_ID", "");
object.icon(iconname, iconclass, iconid);
}
bool MagPlus::gribloop(magics::MagRequest& in)
{
-#ifdef MAGICS_GRIB
+#ifdef HAVE_GRIB
MagLog::dev()<< "add gribloop" << endl;
in.print();
string loop("loop");
string mode = get(in, "GRIB_VISIT_MODE", loop);
-
- if ( !magCompare(mode, loop) )
+
+ if ( !magCompare(mode, loop) )
// we assume it is not an animation...
return grib(in);
-
+
string file = get(in, "GRIB_INPUT_FILE_NAME", "");
-
+
in("GRIB_LOOP_PATH") = file.c_str();
VisualAnimation* action = new VisualAnimation();
top()->push_back(action);
- push(action);
-
+ push(action);
+
GribLoopWrapper grib;
grib.set(in);
setIconInfo(in, *grib.object());
-
+
action->loop(grib.object());
#else
MagLog::dev()<< "can NOT add gribloop (disabled in Magics!)" << endl;
@@ -935,28 +954,28 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
{
MagLog::dev()<< "add rasterloop" << endl;
in.print();
-
+
VisualAnimation* geoloop = new VisualAnimation();
top()->push_back(geoloop);
push(geoloop);
-
+
ImportPlotWrapper visdef;
visdef.set(in);
-
+
setIconInfo(in, *visdef.object());
ImportLoop* loop = new ImportLoop();
setIconInfo(in, *loop);
geoloop->loop(loop);
geoloop->visdef(visdef.object());
-
+
in.countValues("RASTERS");
-
+
magics::MagRequest& rasters = in.getSubRequest("RASTERS");
rasters.print();
- //At this point we do not know the exact type,
+ //At this point we do not know the exact type,
//later we refine it
loop->setInfo("_datatype","RASTERLOOP");
@@ -972,7 +991,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
rasters("IMPORT_FILE_NAME") = path;
rasters("IMPORT_FORMAT") = rasters("IMPORT_FILE_TYPE");
rasters("IMPORT_VALID_TIME") = rasters("TIME");
-
+
ImportActionWrapper object;
object.set(rasters);
@@ -982,7 +1001,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
//WMS related part
string service_name = rasters("SERVICE");
-
+
if(service_name == "WMS")
{
string service_title = rasters("SERVICE_TITLE");
@@ -991,9 +1010,9 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
string description = rasters("DESCRIPTION");
string legend = rasters("LEGEND");
string logo = rasters("LOGO");
- string dimName = rasters("DIM_NAME");
+ string dimName = rasters("DIM_NAME");
string dimValue = rasters("DIM_VALUE");
-
+
if(first)
{
loop->setInfo("_datatype","RASTERLOOP_WMS");
@@ -1023,7 +1042,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
//Temporal dimensions
vector<string> dimNameLst,dimValueLst;
-
+
std::stringstream ssN(dimName);
std::string item;
@@ -1031,7 +1050,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
{
dimNameLst.push_back(item);
}
-
+
std::stringstream ssV(dimValue);
while(std::getline(ssV, item,'/'))
{
@@ -1074,7 +1093,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
object.object()->setInfo("time",dataTime);
object.object()->setInfo("dataTime",dataTime);
object.object()->setInfo("time.dataTime",dataTime);
-
+
}
else if(dimNameLst[i] == "DIM_FORECAST")
{
@@ -1087,17 +1106,17 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
object.object()->setInfo("level",dimValueLst[i]);
object.object()->setInfo("vertical.level",dimValueLst[i]);
}
-
+
}
}
}
-
+
loop->add(object.object());
-
+
rasters.advance();
first=false;
@@ -1107,7 +1126,7 @@ bool MagPlus::rasterloop(magics::MagRequest& in)
}
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
bool MagPlus::geoodb(magics::MagRequest& in)
{
MagLog::dev()<< "add geo odb" << endl;
@@ -1118,26 +1137,26 @@ bool MagPlus::geoodb(magics::MagRequest& in)
path = string(odb("PATH"));
}
in("ODB_FILENAME") = path.c_str();
-
+
static map<string, string> types;
- if ( types.empty() )
+ if ( types.empty() )
{
types["ODB_GEO_POINTS"] = "geopoint";
types["ODB_GEO_VECTORS"] = "geovector";
}
-
+
in("ODB_TYPE") = types[in.getVerb()].c_str();
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
-
+ push(action);
+
OdaGeoDecoderWrapper geoodb;
geoodb.set(in);
setIconInfo(in, *geoodb.object());
top()->data(geoodb.object());
//Meta-data
- geoodb.object()->initInfo();
+ geoodb.object()->initInfo();
return false; // do not exit
}
@@ -1152,21 +1171,21 @@ bool MagPlus::xyodb(magics::MagRequest& in)
path = string(odb("PATH"));
}
in("ODB_FILENAME") = path.c_str();
-
+
static map<string, string> types;
if ( types.empty() ) {
types["ODB_XY_POINTS"] = "xypoint";
types["ODB_XY_VECTORS"] = "xyvector";
types["ODB_XY_BINNING"] = "xybinning";
}
-
+
in("ODB_TYPE") = types[in.getVerb()].c_str();
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
-
+ push(action);
+
OdaXYDecoderWrapper xyodb;
-
+
magics::MagRequest& bin = in.getSubRequest("ODB_BINNING");
if(bin)
{
@@ -1177,10 +1196,10 @@ bool MagPlus::xyodb(magics::MagRequest& in)
{
in("ODB_BINNING") = "off";
bin("ODB_BINNING") = "off";
- }
- xyodb.set(in);
- xyodb.set(bin);
-
+ }
+ xyodb.set(in);
+ xyodb.set(bin);
+
setIconInfo(in, *xyodb.object());
top()->data(xyodb.object());
geographical_ = false;
@@ -1192,7 +1211,7 @@ bool MagPlus::xyodb(magics::MagRequest& in)
}
#endif
-#ifdef MAGICS_NETCDF
+#ifdef HAVE_NETCDF
static map<string, string> nctypes;
void checknctypes() {
@@ -1234,16 +1253,16 @@ bool MagPlus::netcdf(magics::MagRequest& in)
VisualAnimation* action = new VisualAnimation();
top()->push_back(action);
- push(action);
-
+ push(action);
+
NetcdfDecoderWrapper geonet;
geonet.set(in);
-
+
NetcdfLoop* loop = new NetcdfLoop(geonet.object());
setIconInfo(in, *geonet.object());
setIconInfo(in, *loop);
action->loop(loop);
-
+
return false; // do not exit
}
@@ -1303,38 +1322,56 @@ bool MagPlus::geopoints(magics::MagRequest& in)
// Extract the path ..
magics::MagRequest& record = in.getSubRequest("RECORD");
-
+
string path = record("PATH");
in("GEO_INPUT_FILE_NAME") = path;
in.print();
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
-
+ push(action);
+
GeoPointsDecoderWrapper geopoints;
geopoints.set(in);
setIconInfo(in, *geopoints.object());
top()->data(geopoints.object());
//Meta-data
- geopoints.object()->initInfo();
-
+ geopoints.object()->initInfo();
+
return false; // do not exit
}
+
+bool MagPlus::geojson(magics::MagRequest& in)
+{
+ VisualAction* action = new VisualAction();
+ top()->push_back(action);
+ push(action);
+
+ GeoJSonWrapper geo;
+ geo.set(in);
+ setIconInfo(in, *geo.object());
+ top()->data(geo.object());
+
+ //Meta-data
+ geo.object()->initInfo();
+
+ return false; // do not exit
+}
+
bool MagPlus::bufr(magics::MagRequest& in)
{
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
/*
// Extract the path ..
magics::MagRequest record = in("RECORD");
-
+
in("GEO_INPUT_FILE_NAME") = record("PATH");
*/
in.print();
VisualAction* action = new VisualAction();
top()->push_back(action);
- push(action);
-
+ push(action);
+
ObsDecoderWrapper obs;
obs.set(in);
top()->data(obs.object());
@@ -1349,16 +1386,16 @@ bool MagPlus::symbol(magics::MagRequest& in)
}
string verb = in.getVerb();
if ( verb == "PSYMBPLUS" ) {
- in("SYMBOL_TABLE_MODE") = "advanced";
- in("SYMBOL_TYPE") = "marker";
- }
-
- FortranAutomaticLegendVisitor* node = new FortranAutomaticLegendVisitor();
+ in("SYMBOL_TABLE_MODE") = "advanced";
+ in("SYMBOL_TYPE") = "marker";
+ }
+
+ FortranAutomaticLegendVisitor* node = new FortranAutomaticLegendVisitor();
LegendMethod* method = new ContinuousLegendMethod();
node->method_ = auto_ptr<LegendMethod>(method);
node->getReady();
//top()->legend(node);
- if ( geographical_ ) {
+ if ( geographical_ ) {
SymbolPlottingWrapper symbol;
symbol.set(in);
setIconInfo(in, *symbol.object());
@@ -1391,15 +1428,15 @@ bool MagPlus::graph(magics::MagRequest& in)
bool MagPlus::obs(magics::MagRequest& in)
{
-#ifdef MAGICS_BUFR
+#ifdef HAVE_BUFR
ObsPlottingWrapper visdef;
// here we have to set up manullay the parameters because the obs object is more complex!
// This is not the right solution just a workaround before we find a clean solution...
-
+
for (int i = 0; i < in.countParameters(); i++) {
string param = in.getParameter(i);
string val = in(param.c_str());
-
+
ParameterManager::set(param, val);
}
@@ -1407,9 +1444,9 @@ bool MagPlus::obs(magics::MagRequest& in)
visdef.set(in);
MagLog::dev()<< "add obs" << *visdef.object() << endl;
top()->visdef(visdef.object());
- pop();
-
-
+ pop();
+
+
#endif
return false; // do not exit
}
@@ -1459,7 +1496,7 @@ bool MagPlus::dataloop(magics::MagRequest& in)
bool MagPlus::wind(magics::MagRequest& in)
{
-
+
WindWrapper wind;
wind.set(in);
@@ -1479,13 +1516,13 @@ bool MagPlus::wind(magics::MagRequest& in)
bool MagPlus::visdef(magics::MagRequest& in)
{
MagLog::dev()<< "found visdef" << endl;
-
+
MagRequest& visdefs = in.getSubRequest("ACTIONS");
-
+
visdefs.print();
bool dopop = false;
while (visdefs) {
-
+
string verb = visdefs.getVerb();
{
map<string, ObjectCreator >::iterator creator = sceneHandler_->find(verb);
@@ -1553,10 +1590,10 @@ bool MagPlus::multi(magics::MagRequest& in)
bool MagPlus::contour(magics::MagRequest& in)
{
MagLog::dev()<< "add contour" << endl;
-
+
//replace(in, "CONTOUR_LABEL_HEIGHT", 0.3, 0.2);
string legend = get(in, "CONTOUR_LEGEND", "ON");
-
+
ContourWrapper contour;
contour.set(in);
setIconInfo(in, *contour.object());
@@ -1570,14 +1607,14 @@ bool MagPlus::contour(magics::MagRequest& in)
return false; // do not exit
}
-bool MagPlus::ptext(magics::MagRequest& in)
+bool MagPlus::ptext(magics::MagRequest& in)
{
MagLog::dev()<< "add Text" << endl;
in.print();
sceneCreators_["MLEGEND"] = &MagPlus::ignore;
replace(in, "TEXT_REFERENCE_CHARACTER_HEIGHT", 2.0 , "TEXT_FONT_SIZE", 0.3);
- replace_string(in, "TEXT_COLOUR", "BLUE", "navy");
+ replace_string(in, "TEXT_COLOUR", "BLUE", "navy");
in("TEXT_HTML") = "on";
text(in);
legend(in);
@@ -1585,25 +1622,25 @@ bool MagPlus::ptext(magics::MagRequest& in)
return false; // do not exit
}
-bool MagPlus::text(magics::MagRequest& in)
+bool MagPlus::text(magics::MagRequest& in)
{
-
+
MagLog::dev()<< "add Text-->" << endl;
in.print();
MagLog::dev()<< "<--add Text" << endl;
string mode = get(in, "TEXT_MODE", "automatic");
-
-
+
+
in("TEXT_HTML") = "on";
TextVisitor* node;
if (magCompare(mode, "positional") )
node = new FortranPositionalTextVisitor();
- else
- node = new FortranAutomaticTextVisitor();
-
+ else
+ node = new FortranAutomaticTextVisitor();
+
TextVisitorWrapper helper(node);
- helper.set(in);
+ helper.set(in);
top()->text(node);
@@ -1613,7 +1650,7 @@ bool MagPlus::text(magics::MagRequest& in)
bool MagPlus::legend(magics::MagRequest& in)
{
-
+
MagLog::dev()<< "add legend-->" << endl;
in.print();
MagLog::dev()<< "<--add legend" << endl;
@@ -1622,12 +1659,12 @@ bool MagPlus::legend(magics::MagRequest& in)
LegendVisitor* legend;
if ( magCompare(mode, "positional") ) {
legend = new FortranPositionalLegendVisitor();
-
+
}
- else
+ else
legend = new FortranAutomaticLegendVisitor();
LegendVisitorWrapper helper(legend);
- helper.set(in);
+ helper.set(in);
top()->legend(legend);
return false; // do not exit
}
@@ -1644,18 +1681,18 @@ bool MagPlus::device(magics::MagRequest& in)
XmlNode* driver = 0;
if ( !in.countValues("FORMAT") ) return false;
string fmt = in("FORMAT");
-
-
+
+
string format(fmt);
-
+
if ( format == "POSTSCRIPT") {
-
+
map<string, string> attributes;
attributes["output_fullname"] = string(in("FILE"));
-
+
driver = new XmlNode("ps", attributes);
}
-
+
output_.set(*driver, drivers_);
if ( driver) delete(driver);
return false; // do not exit
@@ -1668,7 +1705,7 @@ void MagPlus::execute( magics::MagRequest& in)
in.print();
cout << "<---MagPlus::execute" << endl;
try {
- // Start from a fersh tree!
+ // Start from a fersh tree!
#ifndef MAG_NEXT
if (root_)
{
@@ -1695,7 +1732,7 @@ void MagPlus::execute( magics::MagRequest& in)
if ( (this->*creator->second)(request) ) return;
}
}
- {
+ {
map<string, ObjectCreator >::iterator creator = driverCreators_.find(verb);
if ( creator != driverCreators_.end() ) {
magics::MagRequest& request = in.justOneRequest();
@@ -1708,13 +1745,13 @@ void MagPlus::execute( magics::MagRequest& in)
MagLog::warning() << "Sorry, nothing to to display!" << endl;
return;
}
- assert(root_);
+ ASSERT(root_);
root_->getReady();
drivers_.setDriversWidth(root_->absoluteWidth());
drivers_.setDriversHeight(root_->absoluteHeight());
root_->mode(mode_);
-
+
root_->execute();
drivers_.openDrivers();
@@ -1727,7 +1764,7 @@ void MagPlus::execute( magics::MagRequest& in)
/*! \todo Why is this MagMagException empty??? */
MagLog::error() << "Something went really wrong!" << e << endl;
- }
+ }
}
@@ -1735,18 +1772,54 @@ void MagPlus::execute( magics::MagRequest& in)
void MagPlus::notify(MagicsEvent& event)
{
MagLog::dev()<< "NOTIFY---" << event << endl;
- for (vector<MagicsObserver*>::iterator observer = observers_.begin(); observer != observers_.end(); ++observer)
+ for (vector<MagicsObserver*>::iterator observer = observers_.begin(); observer != observers_.end(); ++observer)
event.notify(**observer);
}
void MagPlus::unregisterObserver(MagicsObserver* observer)
{
- observers_.erase(std::remove_if(observers_.begin(), observers_.end(),
+ observers_.erase(std::remove_if(observers_.begin(), observers_.end(),
bind2nd(std::equal_to<MagicsObserver*>(), observer)), observers_.end());
-
+
}
+void setDouble(const string& key, const ParamJSon& json, MagRequest& out)
+{
+ ParamJSon::const_iterator param = json.find(key);
+ if ( param != json.end() )
+ out(key) = tonumber(param->second);
+}
+
+void setString(const string& key, const ParamJSon& json, MagRequest& out)
+{
+ ParamJSon::const_iterator param = json.find(key);
+ if ( param != json.end() )
+ out(key) = param->second;
+}
+void MagPlus::decode(MagRequest& out, const string& json)
+{
+ ParamJSon params(json);
+/*
+ '{"subpage_lower_left_latitude" : "40.8424",\
+ "subpage_lower_left_longitude" : "-20.5033",\
+ "subpage_map_area_definition" : "corners",\
+ "subpage_map_hemisphere" : "north",\
+ "subpage_map_projection" : "polar_stereographic",\
+ "subpage_map_vertical_longitude" : "0",\
+ "subpage_upper_right_latitude" : "62.073",\
+ "subpage_upper_right_longitude" : "28.3054"}'
+*/
+ setDouble("subpage_lower_left_latitude", params, out);
+ setDouble("subpage_lower_left_longitude", params, out);
+ setString("subpage_map_area_definition", params, out);
+ setString("subpage_map_hemisphere", params, out);
+ setString("subpage_map_projection", params, out);
+ setDouble("subpage_map_vertical_longitude", params, out);
+ setDouble("subpage_upper_right_latitude", params, out);
+ setDouble("subpage_upper_right_longitude", params, out);
+
+}
//_____________________________________________________________________
diff --git a/src/libMagWrapper/MagPlus.h b/src/libMagWrapper/MagPlus.h
index 2461ecd..fd89184 100644
--- a/src/libMagWrapper/MagPlus.h
+++ b/src/libMagWrapper/MagPlus.h
@@ -38,6 +38,8 @@ public:
void execute(MagRequest&);
+ static void decode(MagRequest&, const string&);
+
void registerObserver(MagicsObserver* observer) { observers_.push_back(observer); }
void unregisterObserver(MagicsObserver* observer);
//! Notify drivers about an event (GUI -> Qt)
@@ -82,13 +84,14 @@ protected:
bool oldcoastlines(magics::MagRequest&);
bool axis(magics::MagRequest&);
bool grib(magics::MagRequest&);
+ bool geojson(magics::MagRequest&);
bool gribloop(magics::MagRequest&);
bool rasterloop(magics::MagRequest&);
bool dataloop(magics::MagRequest&);
bool bufr(magics::MagRequest&);
bool visdef(magics::MagRequest&);
-#ifdef MAGICS_ODB
+#ifdef HAVE_ODB
bool geoodb(magics::MagRequest&);
bool xyodb(magics::MagRequest&);
#endif
@@ -123,6 +126,7 @@ protected:
bool pngdriver(magics::MagRequest&);
bool svgdriver(magics::MagRequest&);
bool kmldriver(magics::MagRequest&);
+ bool geojsondriver(magics::MagRequest&);
bool psdriver(magics::MagRequest&);
bool epsdriver(magics::MagRequest&);
diff --git a/src/libMagWrapper/MagRequest.h b/src/libMagWrapper/MagRequest.h
index 98c6f09..eb97cb0 100644
--- a/src/libMagWrapper/MagRequest.h
+++ b/src/libMagWrapper/MagRequest.h
@@ -24,14 +24,16 @@ public:
virtual operator double() const { return dvalue_; }
virtual operator string() const { return svalue_;}
virtual operator int() const { return ivalue_; }
+ virtual operator long int() const { return lvalue_; }
virtual MagParam& operator=(int i) { ivalue_ = i; cout << "set int" << ivalue_ << endl; return *this;}
virtual MagParam& operator=(string s) { svalue_ = s; cout << "set string" << svalue_ << endl; return *this;}
virtual MagParam& operator=(double d) { dvalue_ = d; cout << "set double" << dvalue_ << endl; return *this; }
-
+ virtual MagParam& operator=(long int i) { ivalue_ = i; cout << "set long int" << ivalue_ << endl; return *this; }
protected:
string svalue_;
int ivalue_;
+ int lvalue_;
double dvalue_;
};
diff --git a/src/magics.h b/src/magics.h
index 2c6a4ea..fa81581 100644
--- a/src/magics.h
+++ b/src/magics.h
@@ -40,7 +40,7 @@
#include <climits>
// do the export restriction only if NOT for Metview
-#ifndef MAGICS_METVIEW
+#ifndef HAVE_METVIEW
#ifdef WIN32
#define MAGICS_IMPORT __declspec(dllimport)
@@ -175,6 +175,7 @@ public:
typedef magvector<string> stringarray;
typedef magvector<int> intarray;
+typedef magvector<long int> longintarray;
typedef magvector<double> doublearray;
typedef magvector<double> floatarray;
@@ -185,10 +186,10 @@ enum Position { M_AUTOMATIC, M_TOP , M_BOTTOM , M_LEFT, M_RIGHT};
enum VerticalAlign { MNORMAL, MTOP, MCAP, MHALF, MBASE, MBOTTOM };
//enum VerticalAlign { MBASE, MTOP, MHALF, MBOTTOM }; // if change you need to change also share/magics/PostScriptMacros2.dat
enum Shading { M_SH_NONE, M_SH_SOLID, M_SH_HATCH, M_SH_DOT };
-enum ArrowPosition { M_TAIL, M_CENTRE };
+enum ArrowPosition { M_TAIL, M_CENTRE, M_HEAD_ONLY};
enum DisplayType { ABSOLUTE, INLINE, BLOCK, NONE, HIDDEN };
enum ListPolicy { M_LASTONE, M_CYCLE };
-enum GraphicsFormat {PS, EPS, PDF, SVG, KML, PNG, X, CPS, CSVG, GIF, AGIF, JPG, QT};
+enum GraphicsFormat {PS, EPS, PDF, SVG, KML, PNG, X, CPS, CSVG, GIF, AGIF, JPG, QT, GEOJSON};
enum AxisAutomaticSetting {m_off, m_both, m_min_only, m_max_only};
/*
diff --git a/src/magics.pc.in b/src/magics.pc.in
deleted file mode 100644
index a1c5619..0000000
--- a/src/magics.pc.in
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=${prefix}
-libdir=@CMAKE_INSTALL_PREFIX@/lib
-includedir=@CMAKE_INSTALL_PREFIX@/include
-
-Name: Magics
-Description: Multi-platform meteorological graphics library
-Version: @MAGICS_VERSION@
-
-# @PKGCONFIG_REQUIRES@: @MAGICS_REQUIRES@
-Libs: -L${libdir} -lMagPlus
-Libs.private: @MAGICS_EXTRA_LIBS@
-Cflags: -I${includedir} @MAGICS_EXTRA_INCLUDES@
diff --git a/src/magics_config.h.in b/src/magics_config.h.in
index b6642d9..638c501 100644
--- a/src/magics_config.h.in
+++ b/src/magics_config.h.in
@@ -71,14 +71,16 @@
#cmakedefine MAGICS_ALLHEADERS
/* Turn off the BUFR support */
-#cmakedefine MAGICS_BUFR
+#cmakedefine HAVE_BUFR
/* Turn on the Cairo output support */
-#cmakedefine MAGICS_CAIRO
+#cmakedefine HAVE_CAIRO
/* Period of Copyright. */
#cmakedefine MAGICS_COPYRIGHT_PERIOD
+/* Turn on the GeoTIFF output support */
+#cmakedefine HAVE_GEOTIFF
/* Defines GIF output is supported. */
#cmakedefine MAGICS_GIF
@@ -87,7 +89,7 @@
#cmakedefine MAGICS_GIF_ANIMATED
/* Turn off the GRIB 1/2 support */
-#cmakedefine MAGICS_GRIB
+#cmakedefine HAVE_GRIB
/* Install path. */
#define MAGICS_INSTALL_PATH "@CMAKE_INSTALL_PREFIX@"
@@ -111,22 +113,22 @@
#cmakedefine MAGICS_METGRAM
/* Installation used by metview */
-#cmakedefine MAGICS_METVIEW
+#cmakedefine HAVE_METVIEW
/* Name of this package. */
#define MAGICS_NAME "@MAGICS_NAME@"
/* Turn off the netCDF support */
-#cmakedefine MAGICS_NETCDF
+#cmakedefine HAVE_NETCDF
/* Turn off the ODB support */
-#cmakedefine MAGICS_ODB
+#cmakedefine HAVE_ODB
/* Gives the list of output formats */
#cmakedefine MAGICS_OUTPUTS
-/* Enable Python interface (based on swik). */
-#cmakedefine MAGICS_PYTHON
+/* Enable Python interface (based on SWIG). */
+#cmakedefine HAVE_PYTHON
/* Turn on Qt related modules. */
#cmakedefine MAGICS_QT
@@ -141,7 +143,7 @@
#define MAGICS_SITE "@MAGICS_SITE@"
/* Turn off the SPOT support */
-#cmakedefine MAGICS_SPOT
+#cmakedefine HAVE_SPOT
/* Turn on/off thread support. */
#cmakedefine MAGICS_THREADS
diff --git a/src/oda/OdaDecoder.cc b/src/oda/OdaDecoder.cc
index 5243be2..0b21785 100644
--- a/src/oda/OdaDecoder.cc
+++ b/src/oda/OdaDecoder.cc
@@ -31,19 +31,11 @@
#include <map>
#include <set>
-#ifdef ODB_ECKIT
- #include <odb_api/ColumnType.h>
- #include <odb_api/Reader.h>
-#else
- #include <odblib/odb_api.h>
-#endif
+#include <odb_api/ColumnType.h>
+#include <odb_api/Reader.h>
extern "C" {
-#ifdef ODB_ECKIT
- #include <odb_api/odbcapi.h>
-#else
- #include <odblib/odbcapi.h>
-#endif
+#include <odb_api/odbcapi.h>
}
diff --git a/src/params/BaseDriver.xml b/src/params/BaseDriver.xml
index 47d8b8c..dcc3484 100644
--- a/src/params/BaseDriver.xml
+++ b/src/params/BaseDriver.xml
@@ -8,13 +8,8 @@
<documentation>Defines a title for the output which gets displayed if the format supports it. </documentation>
</parameter>
-
-
-
-
-
<parameter member="name" to="string" default="" from="string" name="output_name">
- <documentation>Defines the root of output filename. </documentation>
+ <documentation>Defines the root of output filename.</documentation>
</parameter>
<parameter member="firstnumber" to="bool" default="on" from="string" name="output_name_first_page_number">
@@ -46,25 +41,26 @@
</parameter>
<parameter member="debug" to="bool" default="off" from="string" name="output_debug">
- <documentation>Defines if extra debug information are written in the output file (PS, EPS, SVG) or console (GIF/PNG).</documentation>
- <release>2.1 </release>
+ <documentation>Defines if extra debug information are written in the output file (PS, EPS, SVG) or console (PNG).</documentation>
+ <release>2.1</release>
</parameter>
<parameter member="width" to="int" default="800" from="int" name="output_width">
<documentation>Defines the width of the image in pixels.(For GD and SVG)</documentation>
</parameter>
+<!--
<parameter member="resolution" to="int" default="300" from="int" name="output_resolution">
<documentation>Defines the resolution of the (graphical) output in dpi (72 - screen, 300 - print).</documentation>
</parameter>
-
+-->
<parameter member="filelist" to="bool" default="off" from="string" name="output_filelist">
<documentation>Defines if a list of all generated files should be written.</documentation>
- <set name="output_filelist_name" value="on"> </set>
- <release>2.7.10 </release>
+ <set name="output_filelist_name" value="on"></set>
+ <release>2.7.10</release>
</parameter>
<parameter member="filelist_name" to="string" default="magics_outputs.lst" from="string" name="output_filelist_name">
<documentation>Defines the name of the file containing the list of generated files.</documentation>
- <release>2.7.10 </release>
+ <release>2.7.10</release>
</parameter>
<parameter name='output_filelist_reset' from='string' to='bool' member='filelist_reset' default='off'>
diff --git a/src/params/CMakeLists.txt b/src/params/CMakeLists.txt
index 916dfaa..43b4c96 100644
--- a/src/params/CMakeLists.txt
+++ b/src/params/CMakeLists.txt
@@ -77,6 +77,7 @@ IsoLabel.xml
IsoPlot.xml
IsoShading.xml
KMLDriver.xml
+GeoJsonDriver.xml
LabelPlotting.xml
ObsPlotting.xml
@@ -197,7 +198,7 @@ XHyperCoordinate.xml
XLogarithmicCoordinate.xml
XRegularCoordinate.xml
XYList.xml
-
+GeoJSon.xml
YCoordinate.xml
YDateCoordinate.xml
YHyperCoordinate.xml
@@ -255,6 +256,7 @@ ObsStatDecoder.xml
SimplePolyline.xml
SimplePolylineInput.xml
WrepJSon.xml
+
WrepRootNode.xml
XmlBasicNode.xml
XmlRootNode.xml
@@ -263,7 +265,7 @@ XmlViewNode.xml
)
-if( MAGICS_GRIB )
+if( HAVE_GRIB )
list( APPEND _common_xmls GribAddressByteMode.xml
GribAddressMode.xml
GribAddressRecordMode.xml
@@ -274,7 +276,7 @@ if( MAGICS_GRIB )
)
endif()
-if( MAGICS_NETCDF )
+if( HAVE_NETCDF )
list( APPEND _common_xmls
NetcdfDecoder.xml
NetcdfGeoMatrixInterpretor.xml
@@ -288,13 +290,13 @@ if( MAGICS_NETCDF )
NetcdfXYpointsInterpretor.xml )
endif()
-if ( MAGICS_ODB )
+if ( HAVE_ODB )
list ( APPEND _common_xmls
OdaGeoDecoder.xml
OdaXYDecoder.xml )
endif()
-if( MAGICS_CAIRO )
+if( HAVE_CAIRO )
list( APPEND _common_xmls CairoDriver.xml )
endif()
diff --git a/src/params/CairoDriver.xml b/src/params/CairoDriver.xml
index e28e6a8..39ef8c6 100644
--- a/src/params/CairoDriver.xml
+++ b/src/params/CairoDriver.xml
@@ -15,9 +15,13 @@
<parameter xml="antialias" from="string" name="output_cairo_antialias" default="on" member="antialias" to="string" values="on/off">
<documentation>Defines if lines are antialiased (only for PNG).</documentation>
</parameter>
-<!--
+
+ <parameter xml="palette" from="string" name="output_cairo_palette" default="off" member="palette" to="string" values="on/off">
+ <documentation>Defines if PNG uses palettes to reduce file size.</documentation>
+ </parameter>
+
<parameter xml="quality" name='output_geotiff_quality' from='int' to='int' member='quality' default='1'>
<documentation for_docs='no'>Defines the quality of GeoTiff output. The default of 1. Should be a value in the range 0-10.</documentation>
</parameter>
- -->
+
</class></magics>
diff --git a/src/params/FortranViewNode.xml b/src/params/FortranViewNode.xml
index a040d0f..3938899 100644
--- a/src/params/FortranViewNode.xml
+++ b/src/params/FortranViewNode.xml
@@ -78,6 +78,10 @@
<release>Magics++2.4 </release>
<documentation> Y-Coordinate of upper left hand corner of subpage </documentation>
</parameter>
+ <parameter from="string" name="subpage_clipping" default="off" member="clipping" to="bool">
+
+ <documentation> Apply a clipping to the subpage to avoid any symbol, flag or arrow to go outside of the plotting area</documentation>
+ </parameter>
<parameter member="background" to="Colour" default="white" from="string" name="subpage_background_colour">
diff --git a/src/params/GeoJSon.xml b/src/params/GeoJSon.xml
new file mode 100644
index 0000000..0531572
--- /dev/null
+++ b/src/params/GeoJSon.xml
@@ -0,0 +1,15 @@
+<magics>
+<class xmltag="geojson" name="GeoJSon" directory="web" prefix="geojson" action="pgeojson" include="GeoJSon.h">
+ <parameter member="type" to="string" default="file" from="string" name="geojson_input_type" values='string/file'>
+ <documentation> data are in a file ( file ) or passed as a string (string) </documentation>
+ </parameter>
+
+ <parameter member="path" to="string" default="" from="string" name="geojson_input_filename">
+ <documentation> Path to the file containing the GeoJson data </documentation>
+ </parameter>
+ <parameter member="input" to="string" default="{}" from="string" name="geojson_input">
+ <documentation> String containing the GeoJson data </documentation>
+ </parameter>
+</class>
+
+</magics>
diff --git a/src/params/GeoJsonDriver.xml b/src/params/GeoJsonDriver.xml
new file mode 100644
index 0000000..8536c2d
--- /dev/null
+++ b/src/params/GeoJsonDriver.xml
@@ -0,0 +1,28 @@
+<magics>
+<class inherits="BaseDriver" xmltag="GeoJson" name="GeoJsonDriver" directory="drivers" prefix="GeoJson" action="GeoJson">
+ <documentation for_docs="no">
+ This output driver produces output in the GeoJson format.
+
+ See also the parameters for the BaseDriver.
+ </documentation>
+
+ <parameter member="zip" to="bool" default="off" from="string" name="geojson_zip">
+ <documentation>Defines if output files will be zipped.</documentation>
+ </parameter>
+
+ <parameter member="description" to="string" default="Generated by Magics++" from="string" name="geojson_description">
+ <documentation>Short description for the product.</documentation>
+ </parameter>
+
+ <parameter member="author" to="string" default="" from="string" name="geojson_author">
+ <documentation>Gives the author of the product.</documentation>
+ </parameter>
+
+ <parameter member="link" to="string" default="" from="string" name="geojson_link">
+ <documentation>Gives the HTTP link to the product (Example: http://www.ecmwf.int/products).</documentation>
+ </parameter>
+
+ <parameter member="coastlines" to="bool" default="off" from="string" name="geojson_coastlines">
+ <documentation>Determines if coastlines are written by Magics or not. Default is OFF because GIS systems have often their own coastlines.</documentation>
+ </parameter>
+</class></magics>
diff --git a/src/params/GeoPointsDecoder.xml b/src/params/GeoPointsDecoder.xml
index 179788a..652bd19 100644
--- a/src/params/GeoPointsDecoder.xml
+++ b/src/params/GeoPointsDecoder.xml
@@ -4,4 +4,7 @@
<release>Magics++1.1 </release>
<documentation> The name of the input file containing the GeoPoints code field(s) </documentation>
</parameter>
+ <parameter member="missing" to="float" default="3.0E+38" from="float" name="geo_missing_value">
+ <documentation> missing value for geopoints </documentation>
+ </parameter>
</class></magics>
diff --git a/src/params/GribDecoder.xml b/src/params/GribDecoder.xml
index d00143e..e3837df 100644
--- a/src/params/GribDecoder.xml
+++ b/src/params/GribDecoder.xml
@@ -33,10 +33,14 @@
<release>Magics++2.10 </release>
<documentation> Apply a scaling offset to the field. </documentation>
</parameter>
- <parameter member="interpolation_method" to="string" default="interpolate" from="string" name="grib_interpolation_method" values='interpolate/nearest' >
- <release>Magics++2.10 </release>
+ <parameter member="interpolation_method" to="string" default="interpolate" from="string" name="grib_interpolation_method" values='interpolate/nearest/nearest_valid' >
+
<documentation> Used for reduced gaussian grid: use an linear interpolation to convert from reduced to regular </documentation>
</parameter>
+ <parameter member="missing_fill_count" to="int" default="1" from="int" name="grib_interpolation_method_missing_fill_count" >
+
+ <documentation> Number of missing values to fill with the nearest valid value </documentation>
+ </parameter>
<parameter from="string" name="grib_text_experiment" visible="false" default="off" member="expver" to="bool">
<release>Magics++0.3 </release>
diff --git a/src/params/GribLoop.xml b/src/params/GribLoop.xml
index 61eabf6..26d8fd7 100644
--- a/src/params/GribLoop.xml
+++ b/src/params/GribLoop.xml
@@ -2,7 +2,7 @@
<class xmltag="gribloop" name="GribLoop" directory="decoders" prefix="grib" action="pgrib" include="GribDecoder.h">
<documentation>
The purpose of the GRIB loop is to easily create an animation. This feature
- is only available in MagML.
+ is only available in MagML.
</documentation>
<parameter member="address_mode" to="GribAddressMode" default="record" from="string" name="grib_file_address_mode">
<option xml="record" fortran="record" include="GribAddressMode.h" name="GribAddressRecordMode"> </option>
@@ -12,17 +12,17 @@
<parameter member="dimension" to="intarray" default="intarray()" from="intarray" name="grib_dimension">
<documentation> Metview:dimension of the input : 1 for field, 2 for wind </documentation>
</parameter>
-
- <parameter member="dim_1" to="intarray" default="intarray()" from="intarray" name="grib_position_1">
+
+ <parameter member="dim_1" to="longintarray" default="longintarray()" from="longintarray" name="grib_position_1">
<documentation> Metview:position of the fields for x component in the fieldset </documentation>
</parameter>
- <parameter member="dim_2" to="intarray" default="intarray()" from="intarray" name="grib_position_2">
+ <parameter member="dim_2" to="longintarray" default="longintarray()" from="longintarray" name="grib_position_2">
<documentation> Metview:position of the fields for y component in the fieldset </documentation>
</parameter>
- <parameter member="dim_colour" to="intarray" default="intarray()" from="intarray" name="grib_position_colour">
+ <parameter member="dim_colour" to="longintarray" default="longintarray()" from="longintarray" name="grib_position_colour">
<documentation> Metview:position of the fields for colour component in the fieldset </documentation>
</parameter>
- <parameter member="dim" to="intarray" default="intarray()" from="intarray" name="grib_position">
+ <parameter member="dim" to="longintarray" default="longintarray()" from="longintarray" name="grib_position">
<documentation> Metview:position of the fields to plot in the fieldset </documentation>
</parameter>
<parameter member="path" to="string" default="" from="string" name="grib_loop_path">
@@ -49,10 +49,15 @@
<release>Magics++2.10 </release>
<documentation> Apply a scaling offset to the field. </documentation>
</parameter>
- <parameter member="interpolation_method" to="string" default="interpolate" from="string" name="grib_interpolation_method" values='interpolate/nearest' >
+ <parameter member="interpolation_method" to="string" default="interpolate" from="string" name="grib_interpolation_method" values='interpolate/nearest/nearest_valid' >
<release>Magics++2.10 </release>
<documentation> Used for reduced gaussian grid: use an linear interpolation to convert from reduced to regular </documentation>
</parameter>
+ <parameter member="missing_fill_count" to="int" default="1" from="int" name="grib_interpolation_method_missing_fill_count" >
+
+ <documentation> Number of missing values to fill with the nearest valid value </documentation>
+ </parameter>
+
<parameter member="wind_mode" to="WindMode" default="uv" from="string" name="grib_wind_mode">
<documentation> The incoming wind field may contain data other than wind components, e.g. wave height and direction.
grib_wind_mode should be set to indicate how to interpret the incoming wind field,
diff --git a/src/params/InputMatrix.xml b/src/params/InputMatrix.xml
index 46fe421..9e5b2b0 100644
--- a/src/params/InputMatrix.xml
+++ b/src/params/InputMatrix.xml
@@ -25,6 +25,10 @@
<option xml="irregular" fortran="nonregular" include="InputMatrixInterpretor.h" name="InputMatrixIrregularInterpretor"> </option>
<documentation> How data is organized in the input field (REGULAR /IRREGULAR/) </documentation>
</parameter>
+ <parameter xml="input_mars_metadata" from="string" name="input_mars_metadata" default="{}" member="metadata" to="string">
+
+ <documentation> Json Object that contains metadata to descrive the the input data: will be used by the automatic eccharts contouring </documentation>
+ </parameter>
<parameter xml="input_field_subpage_mapping" from="string" name="input_field_subpage_mapping" default="upper_left" member="mapping" to="string">
<documentation> Position of first point of array (1,1) on the subpage, (see text)(UPPER_LEFT / UPPER_RIGHT / LOWER_LEFT / LOWER_RIGHT /
diff --git a/src/params/LabelPlotting.xml b/src/params/LabelPlotting.xml
index 5101a85..a52fdd7 100644
--- a/src/params/LabelPlotting.xml
+++ b/src/params/LabelPlotting.xml
@@ -3,11 +3,12 @@
<documentation>
This object will control the settings of the Map Labels.
</documentation>
- <parameter member="quality" to="string" default="MEDIUM" from="string" name="map_label_quality">
- <documentation>
- Quality of grid labels
- </documentation>
- <release>Magics++0.1 </release>
+
+ <parameter member="font" to="string" default="sansserif" from="string" name="map_label_font">
+ <documentation> Font of grid labels </documentation>
+ </parameter>
+ <parameter member="font_style" to="string" default="normal" from="string" name="map_label_font_style">
+ <documentation> Font of grid labels </documentation>
</parameter>
<parameter member="colour" to="Colour" default="black" from="string" name="map_label_colour">
<documentation>
@@ -18,9 +19,15 @@
<parameter member="height" to="float" default="0.25" from="float" name="map_label_height">
<documentation>
Height og grid labels
- </documentation>
+ </documentation>
<release>Magics++0.1 </release>
</parameter>
+ <parameter member="blanking" to="bool" default="on" from="string" name="map_label_blanking">
+ <documentation>
+ Blanking of the grid labels
+ </documentation>
+
+ </parameter>
<parameter member="latFrequency" to="int" default="1" from="int" name="map_label_latitude_frequency">
<documentation>
diff --git a/src/params/LegendVisitor.xml b/src/params/LegendVisitor.xml
index d27cf2a..e5ac687 100644
--- a/src/params/LegendVisitor.xml
+++ b/src/params/LegendVisitor.xml
@@ -176,7 +176,11 @@
<parameter from="string" name="legend_user_text_10" visible="off" default="" member="text10" to="string">
<documentation> User text to be associated with a legend sub-entry from a multiple entry </documentation>
- </parameter>
+ </parameter>
+ <parameter from="float" name="legend_symbol_height_factor" default="1" member="symbol_factor" to="float" >
+ <documentation> Factor to apply to the symbol_height in the legend </documentation>
+ </parameter>
+
<parameter member="box_x" to="float" default="-1" from="float" name="legend_box_x_position">
<documentation> X coordinate of lower left corner of legend box (Relative to page_x_position) </documentation>
diff --git a/src/params/MarkerShadingTechnique.xml b/src/params/MarkerShadingTechnique.xml
index e3b6d46..b897a00 100644
--- a/src/params/MarkerShadingTechnique.xml
+++ b/src/params/MarkerShadingTechnique.xml
@@ -7,11 +7,20 @@
<parameter member="height" to="floatarray" default="floatarray()" from="floatarray" name="contour_shade_height_table">
<documentation> Height table to be used with MARKER shading technique </documentation>
- <release>0.2 </release>
+
</parameter>
+ <parameter member="type" to="string" default="index" from="string" name="contour_shade_marker_table_type" values="index/name">
+ <documentation> index: using contour_shade_marker_table and definiing the markers by index, name: using contour_shade_marker_name_table and defining the symbols by their names </documentation>
+
+ </parameter>
+
<parameter member="marker" to="intarray" default="intarray()" from="intarray" name="contour_shade_marker_table">
<documentation> Marker table to be used with MARKER shading technique </documentation>
- <release>0.2 </release>
+
+ </parameter>
+ <parameter member="symbol" to="stringarray" default="stringarray()" from="stringarray" name="contour_shade_marker_name_table">
+ <documentation> Marker name table to be used with MARKER shading technique </documentation>
+
</parameter>
</class></magics>
diff --git a/src/params/NetcdfInterpretor.xml b/src/params/NetcdfInterpretor.xml
index b83caeb..aea77be 100644
--- a/src/params/NetcdfInterpretor.xml
+++ b/src/params/NetcdfInterpretor.xml
@@ -18,6 +18,12 @@
<parameter member="field" to="string" default="" from="string" name="netcdf_value_variable">
<documentation>Variable to plot</documentation>
+ </parameter>
+ <parameter member="u_component" to="string" default="" from="string" name="netcdf_x_component_variable">
+ <documentation>x_component for vector plotting</documentation>
+ </parameter>
+ <parameter member="v_component" to="string" default="" from="string" name="netcdf_y_component_variable">
+ <documentation>y_component for vector plotting</documentation>
</parameter>
<parameter member="scaling" to="float" default="1" from="float" name="netcdf_field_scaling_factor">
@@ -26,7 +32,7 @@
<parameter member="offset" to="float" default="0" from="float" name="netcdf_field_add_offset">
<documentation>Offset added to the field values </documentation>
</parameter>
- <parameter member="missing_attribute" to="string" default="missing_value" from="string" name="netcdf_missing_attribute">
+ <parameter member="missing_attribute" to="string" default="_FillValue" from="string" name="netcdf_missing_attribute">
<documentation>Attribute indicating the value used to indicate a missing value in the data </documentation>
</parameter>
<parameter member="reference" to="string" default="0" from="string" name="netcdf_reference_date">
diff --git a/src/params/ObsPlotting.xml b/src/params/ObsPlotting.xml
index 0993a41..fb6cea4 100644
--- a/src/params/ObsPlotting.xml
+++ b/src/params/ObsPlotting.xml
@@ -9,10 +9,10 @@
<documentation> Observation Colour </documentation>
</parameter>
- <parameter member="size" to="float" default="0.2" from="float" name="obs_size">
+ <parameter member="size" to="float" default="0.25" from="float" name="obs_size">
<documentation> size of a single onservation in cm </documentation>
</parameter>
- <parameter member="ring_size" to="float" default="0.2" from="float" name="obs_ring_size">
+ <parameter member="ring_size" to="float" default="-1" from="float" name="obs_ring_size">
<documentation> Size of the station ring in cm </documentation>
</parameter>
@@ -46,7 +46,7 @@
<set name="obs_pressure_tendency_colour" value="on"/>
</parameter>
- <parameter member="pressure_tendency_colour" to="Colour" default="automatic" from="string" name="obs_pressure_tendency_colour">
+ <parameter member="pressure_tendency_colour" to="Colour" default="red" from="string" name="obs_pressure_tendency_colour">
<documentation> Colour used to display the pressure tendency </documentation>
</parameter>
<parameter member="station_ring_visible" to="bool" default="on" from="string" name="obs_station_ring">
diff --git a/src/params/OutputHandler.xml b/src/params/OutputHandler.xml
index 4ae9f13..7b10e59 100644
--- a/src/params/OutputHandler.xml
+++ b/src/params/OutputHandler.xml
@@ -2,13 +2,13 @@
<class action="popen" directory="common" xmltag="output" name="OutputHandler">
<parameter xml="format" from="string" name="output_format" default="ps" member="format" to="string">
- <documentation>Defines the device to be used (ps/gif/svg). </documentation>
- <release>1.2 </release>
+ <documentation>Defines the device to be used (ps/png/pdf/svg/kml).</documentation>
+ <release>1.2</release>
</parameter>
<parameter xml="formats" from="stringarray" name="output_formats" default="stringarray()" member="formats" to="stringarray">
- <documentation>Defines the list of devices to be used (ps/gif/svg). </documentation>
- <release>1.2 </release>
+ <documentation>Defines the list of devices to be used (ps/png/pdf/svg/kml).</documentation>
+ <release>1.2</release>
</parameter>
</class></magics>
diff --git a/src/params/SVGDriver.xml b/src/params/SVGDriver.xml
index 175e394..9447ea6 100644
--- a/src/params/SVGDriver.xml
+++ b/src/params/SVGDriver.xml
@@ -3,8 +3,8 @@
<documentation for_docs="no">
The output driver produces vector graphics in the SVG format. See also the parameters for the Base Driver.
</documentation>
- <parameter from="string" name="output_svg_logo_location" default="inline" member="logoLocation" to="string" values="inline/share/www/local">
- <documentation>Sets where the (ECMWF) logo can be found. Possible values are 'inline'(default),'share', 'www' or 'local'.</documentation>
+ <parameter from="string" name="output_svg_logo_location" default="inline" member="logoLocation" to="string" values="inline/share/local">
+ <documentation>Sets where the (ECMWF) logo can be found. Possible values are 'inline'(default),'share' or 'local'.</documentation>
</parameter>
<parameter member="desc" to="string" default="" from="string" name="output_svg_desc">
<documentation>Defines a text describing the content of the SVG output.</documentation>
diff --git a/src/params/Streamlines.xml b/src/params/Streamlines.xml
index 411cd50..e668747 100644
--- a/src/params/Streamlines.xml
+++ b/src/params/Streamlines.xml
@@ -1,40 +1,30 @@
<magics>
<class inherits="WindPlotting" name="Streamlines" directory="visualisers" prefix="wind/wind_streamlines" action="pwind" doc_inherits="no">
<documentation>
- MAGICS parameters exist to control the calculation and plotting of streamlines.
+ Magics parameters exist to control the calculation and plotting of streamlines.
</documentation>
-
<parameter member="min_density" to="float" default="1" from="float" name="wind_streamline_min_density">
- <documentation>
- the minimum number of streamlines to be plotted in one square cm of the user's subpage
- </documentation>
+ <documentation>The minimum number of streamlines to be plotted in one square cm of the user's subpage</documentation>
</parameter>
-
<parameter member="min_speed" to="float" default="1" from="float" name="wind_streamline_min_speed">
- <documentation>
- wind speed below which streamline plotting will be stopped
- </documentation>
+ <documentation>Wind speed below which streamline plotting will be stopped</documentation>
</parameter>
-
<parameter member="thickness" to="int" default="2" from="int" name="wind_streamline_thickness">
- <documentation>
- thickness of streamlines
- </documentation>
+ <documentation>Thickness of streamlines</documentation>
</parameter>
<parameter member="colour" to="Colour" default="blue" from="string" name="wind_streamline_colour">
- <documentation>
- colour of streamlines
- </documentation>
+ <documentation>Colour of streamlines</documentation>
</parameter>
<parameter member="style" to="LineStyle" default="solid" from="string" name="wind_streamline_style">
- <documentation>
- line style of streamlines
- </documentation>
+ <documentation>Line style of streamlines</documentation>
</parameter>
-
-
-
-
-</class></magics>
+ <parameter member="head" to="int" default="1" from="int" name="wind_streamline_head_shape">
+ <documentation>Table number, XY, indicating shape of arrowhead X</documentation>
+ </parameter>
+ <parameter member="ratio" to="float" default="0.2" from="float" name="wind_streamline_head_ratio">
+ <documentation>Table number, XY, indicating style and shape of arrowhead X</documentation>
+ </parameter>
+</class>
+</magics>
diff --git a/src/params/SymbolAdvancedTableMode.xml b/src/params/SymbolAdvancedTableMode.xml
index 1a245f6..4533917 100644
--- a/src/params/SymbolAdvancedTableMode.xml
+++ b/src/params/SymbolAdvancedTableMode.xml
@@ -98,7 +98,10 @@
<documentation> List of markers to be used in symbol plotting </documentation>
<release>2.6 </release>
</parameter>
-
+ <parameter member="markers_names" to="stringarray" default="stringarray()" from="stringarray" name="symbol_advanced_table_marker_name_list">
+ <documentation> List of markers to be used in symbol plotting symbol </documentation>
+ <release>2.6 </release>
+ </parameter>
<parameter member="marker_policy" to="ListPolicy" default="lastone" from="string" name="symbol_advanced_table_marker_list_policy">
<documentation>What to do if the list of markers is smaller than the list of intervals: lastone/cycle </documentation>
<release>2.6 </release>
diff --git a/src/params/SymbolIndividualMode.xml b/src/params/SymbolIndividualMode.xml
index f3a0805..087801f 100644
--- a/src/params/SymbolIndividualMode.xml
+++ b/src/params/SymbolIndividualMode.xml
@@ -68,9 +68,7 @@
<documentation> Font colour. </documentation>
</parameter>
- <parameter member="text_blanking" to="bool" default="off" from="string" name="symbol_text_blanking">
- <documentation> blanking of the text </documentation>
- </parameter>
+
<parameter member="legend_height" to="float" default="-1" from="float" name="symbol_legend_height">
<documentation> If set, the height will be used to plot the symbols in the legend </documentation>
</parameter>
diff --git a/src/params/SymbolPlotting.xml b/src/params/SymbolPlotting.xml
index 2edb336..4364526 100644
--- a/src/params/SymbolPlotting.xml
+++ b/src/params/SymbolPlotting.xml
@@ -112,11 +112,25 @@
<set name="symbol_advanced_table_outlayer_min_value" value="advanced"> </set>
<set name="symbol_advanced_table_outlayer_max_value" value="advanced"> </set>
</parameter>
+ <parameter from="string" name="symbol_marker_mode" default="index" member="marker_mode" to="string" values="index/name/image">
+ <documentation> Method to select a marker : by name, by index, by image : in that case, Magics will use an external image as marker.
+ </documentation>
+ <set name="symbol_marker_index" value="index"> </set>
+ <set name="symbol_advanced_table_marker_name_list" value="name"> </set>
+ <noset name="symbol_marker_name" value="name"> </noset>
+ <set name="symbol_image_path" value="image"> </set>
+ <set name="symbol_image_format" value="image"> </set>
+ <set name="symbol_image_width" value="image"> </set>
+ <set name="symbol_image_height" value="image"> </set>
+ </parameter>
+
<parameter xml="format" from="string" name="symbol_format" default="(automatic)" member="format" to="string">
<documentation> Format used to plot values (MAGICS Format/(AUTOMATIC)) </documentation>
</parameter>
-
+ <parameter member="text_blanking" to="bool" default="off" from="string" name="symbol_text_blanking">
+ <documentation> blanking of the text </documentation>
+ </parameter>
<parameter member="outline" to="bool" default="off" from="string" name="symbol_outline">
<set name="symbol_outline_colour" value="on"> </set>
<set name="symbol_outline_thickness" value="on"> </set>
@@ -160,4 +174,9 @@
<parameter member="connect_style" to="LineStyle" default="solid" from="string" name="symbol_connect_line_style">
<documentation> Line Style of connecting line </documentation>
</parameter>
-</class></magics>
+ <parameter member="legend_only" to="bool" default="off" from="string" name="symbol_legend_only" visible='off'>
+ <documentation> Inform the contour object do generate only the legend and not the plot .. [Web sdpecific] </documentation>
+
+ </parameter>
+</class>
+</magics>
diff --git a/src/params/WrepJSon.xml b/src/params/WrepJSon.xml
index 10d596d..83d6d9c 100644
--- a/src/params/WrepJSon.xml
+++ b/src/params/WrepJSon.xml
@@ -81,5 +81,8 @@
</parameter>
-
+ <parameter member="ignore_keys" to="stringarray" default="stringarray()" from="stringarray" name="wrepjson_ignore_keys" visible='off'>
+ <documentation> List of keys to ignore when reading onput data </documentation>
+
+ </parameter>
</class></magics>
diff --git a/src/visualisers/AxisMethod.h b/src/visualisers/AxisMethod.h
index e911bf5..ce1d794 100644
--- a/src/visualisers/AxisMethod.h
+++ b/src/visualisers/AxisMethod.h
@@ -51,7 +51,7 @@ public:
AxisMethod();
virtual ~AxisMethod();
- AxisMethod* clone() { assert(false); return 0;}
+ AxisMethod* clone() { NOTIMP; return 0;}
virtual void set(const map<string, string>& map) {
AxisMethodAttributes::set(map);
}
diff --git a/src/visualisers/CMakeLists.txt b/src/visualisers/CMakeLists.txt
index dbd53c3..1b5ed24 100644
--- a/src/visualisers/CMakeLists.txt
+++ b/src/visualisers/CMakeLists.txt
@@ -195,7 +195,7 @@ endforeach()
set( visualisers_srcs ${visualisers_srcs} PARENT_SCOPE )
-if ( ENABLE_METVIEW )
+if ( HAVE_METVIEW )
list (APPEND metview_include
visualisers/LegendMethod.h
visualisers/LookupTableMode.h
diff --git a/src/visualisers/CalcStreamlines.cc b/src/visualisers/CalcStreamlines.cc
index cf53af2..2a980d4 100644
--- a/src/visualisers/CalcStreamlines.cc
+++ b/src/visualisers/CalcStreamlines.cc
@@ -20,6 +20,7 @@
#include <stdio.h>
+#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <float.h>
@@ -139,6 +140,7 @@ int CalcStreamlines(int density, const float *dir, const GSStruct *gs, OneLineCl
float dx_2e = dx_2 * 1.001;
float dy_2e = dy_2 * 1.001;
int period_x = gs->period_x;
+ int gs_geo = gs->gs_geo;
//int period_y = gs->period_y;
float *dir_tmp = 0x0;
@@ -150,8 +152,7 @@ int CalcStreamlines(int density, const float *dir, const GSStruct *gs, OneLineCl
abut_x = 1;
}
- // Find out if the grid is on the Earth or no
- int gs_geo = 1; // 0 -> not on Earth
+
// x_min and x_per are used for ShiftPeriod function
float x_min = 0.f, x_per = 360.f; // for grids on the Earth
if( !gs_geo )
@@ -781,8 +782,8 @@ int CalcStreamlines(int density, const float *dir, const GSStruct *gs, OneLineCl
}
else
{
- if( cell_shift == -1 && act_cell % nx == 0 ||
- cell_shift == 1 && act_cell % nx == nx-1 )
+ if( ((cell_shift == -1) && (act_cell % nx == 0)) ||
+ ((cell_shift == 1) && (act_cell % nx == nx-1)) )
break;
act_cell += cell_shift;
}
@@ -826,10 +827,13 @@ int CalcStreamlines(int density, const float *dir, const GSStruct *gs, OneLineCl
{
line->X[k] = x[l];
line->Y[k] = y[l];
+ // std:: << k << " = " << "[" << line->X[k] << ", " << line->Y[k] << "]" << std::endl;
k++;
}
}
+ // std::cout << "-----------------------------------------------------------" << std::endl;
+
linenum++;
OneLineClass** new_str_lines = new OneLineClass*[linenum];
for(int ii=0; ii<linenum-1; ii++)
diff --git a/src/visualisers/CalcStreamlines.h b/src/visualisers/CalcStreamlines.h
index c4ced17..8e73943 100644
--- a/src/visualisers/CalcStreamlines.h
+++ b/src/visualisers/CalcStreamlines.h
@@ -49,6 +49,8 @@ struct GSStruct
// Distance between the gridpoints
float dx;
float dy;
+ // Find out if the grid is on the Earth or no
+ int gs_geo; // 0 -> not on Earth
// Is it periodic? (0/1)
int period_x;
diff --git a/src/visualisers/Coastlines.cc b/src/visualisers/Coastlines.cc
index 94439a8..0557f7c 100644
--- a/src/visualisers/Coastlines.cc
+++ b/src/visualisers/Coastlines.cc
@@ -110,7 +110,7 @@ void Coastlines::visit(SceneLayer& layer, vector<LayoutVisitor*>& visitors)
// First we create the layer!
// and push It to the parent layer!
if (layer.state() == geometry_changed ) {
- assert (layer_);
+ ASSERT (layer_);
layer_->clean();
}
else
diff --git a/src/visualisers/Contour.cc b/src/visualisers/Contour.cc
index 1ab7cb0..43e3b60 100644
--- a/src/visualisers/Contour.cc
+++ b/src/visualisers/Contour.cc
@@ -95,7 +95,10 @@ void Contour::operator()(Data& data, BasicGraphicsObjectContainer& parent)
if(library->checkId(needId,needAttributes))
{
data.visit(needAttributes);
+
+
library->getAttributes(needAttributes,attributes);
+
this->set(attributes);
}
else {
diff --git a/src/visualisers/ContourLibrary.cc b/src/visualisers/ContourLibrary.cc
index b3ad849..ff3583c 100644
--- a/src/visualisers/ContourLibrary.cc
+++ b/src/visualisers/ContourLibrary.cc
@@ -42,22 +42,12 @@ void ContourLibrary::askId(MetaDataCollector& meta)
{
meta["observationDiagnostic"]="";
- /*if(!obstat_)
- obstat_ = new ObstatVisdefManager;
-
- for(int i=0; i < obstat_->keys().size(); i++)
- {
- meta[obstat_->keys().at(i)]="";
- }*/
-
- //meta["shortName"] = "";
- //meta["lev"] = "";
}
bool ContourLibrary::checkId(MetaDataCollector& metaId,MetaDataCollector& metaKey)
{
- //Obstat
+ //Obstat
if(metaId["observationDiagnostic"] !="")
{
if(!setInfoObject("ObstatGrib"))
@@ -83,8 +73,7 @@ bool ContourLibrary::checkId(MetaDataCollector& metaId,MetaDataCollector& metaKe
return true;
- //meta["shortName"] = "";
- //meta["lev"] = "";
+
}
@@ -105,21 +94,6 @@ void ContourLibrary::getAttributes(MetaDataCollector& meta, map<string, string>&
info_->getAttributes(meta,attributes);
}
- /*if(!obstat_)
- obstat_ = new ObstatVisdefManager;
-
- MagLog::dev() << "ContourLibrary::set-->" << endl;
-
- for(map<string,string>::iterator it=meta.begin(); it != meta.end(); it++)
- {
- MagLog::dev() << it.first << "--> " << it.second << endl;
- }
- //MagLog::dev() << "shortName-->" << meta["shortName"] << endl;
- //MagLog::dev() << "level-->" << meta["lev"] << endl;
-
- //attributes["contour_line_colour"] = "red";
-
- obstat_->setVisDefAttributes(meta,attributes);*/
}
diff --git a/src/visualisers/ContourLibrary.h b/src/visualisers/ContourLibrary.h
index 3e36dc7..9de3aab 100644
--- a/src/visualisers/ContourLibrary.h
+++ b/src/visualisers/ContourLibrary.h
@@ -1,12 +1,12 @@
/*! \file ContourLibrary.h
\brief Definition of the Template class ContourLibrary.
-
+
Magics Team - ECMWF 2010
-
+
Started: Fri 16-Jul-2010
-
+
Changes:
-
+
*/
#ifndef ContourLibrary_H
@@ -36,17 +36,17 @@ public:
// se the map to set the contour!
virtual void getAttributes(MetaDataCollector&, map<string, string>&);
-
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
- virtual void print(ostream&) const;
+ virtual void print(ostream&) const;
private:
//! Copy constructor - No copy allowed
ContourLibrary(const ContourLibrary&);
//! Overloaded << operator to copy - No copy allowed
ContourLibrary& operator=(const ContourLibrary&);
-
+
bool setInfoObject(string);
// -- Friends
@@ -86,6 +86,7 @@ public:
s << "]" << endl;
}
s << "read from " << p.path_;
+ return s;
}
};
@@ -116,6 +117,7 @@ public:
s << "]" << endl;
}
s << "read from " << p.path_;
+ return s;
}
};
@@ -130,7 +132,7 @@ public:
// set the meta data to be collected
void askId(MetaDataCollector&);
- bool checkId(MetaDataCollector&,MetaDataCollector&) { false; }
+ bool checkId(MetaDataCollector&,MetaDataCollector&) { return true; }
void setCriteria(MetaDataCollector&, const string&);
// set the map to set the contour!
diff --git a/src/visualisers/CountSelectionType.cc b/src/visualisers/CountSelectionType.cc
index a42213c..0ebc193 100644
--- a/src/visualisers/CountSelectionType.cc
+++ b/src/visualisers/CountSelectionType.cc
@@ -54,7 +54,7 @@ void CountSelectionType::calculate(double min, double max, bool)
double nb = levelCount_-1;
- if ( maxi == mini) {
+ if ( same(maxi,mini) ) {
push_back(mini);
return;
}
@@ -62,7 +62,7 @@ void CountSelectionType::calculate(double min, double max, bool)
double toleranceProportion = (double)tolerance_ / (double)(levelCount_ + 1 + i); // tolerance as a proportion of the number of levels
// we add 'i' here because it will be subtracted at the end (because this is the number
// of levels we will not actually plot, ie the min/max contours).
- if (step == 0) {
+ if ( same(step,0) ) {
// Only one isoline!
push_back(mini);
return;
@@ -125,16 +125,21 @@ void CountSelectionType::calculate(double min, double max, bool)
push_back(mini);
first += inc;
double epsilon = inc/10000.0;
+ if ( same(epsilon, 0) )
+ return;
for (double val = first; val < maxi; val += inc) {
// special case - if the value is close to zero then set it to precisely zero to avoid later formatting issues
if (fabs(val) < epsilon)
push_back(0.0);
+ else if ( same(val, maxi) )
+ push_back(maxi);
else
- push_back(val);
+ push_back(val);
}
- push_back(maxi);
+ if ( maxi != back() )
+ push_back(maxi);
int si = static_cast<int>(size());
diff --git a/src/visualisers/EpsGraph.cc b/src/visualisers/EpsGraph.cc
index 83a9df7..bee6f8f 100644
--- a/src/visualisers/EpsGraph.cc
+++ b/src/visualisers/EpsGraph.cc
@@ -1709,7 +1709,7 @@ CdfGraph::~CdfGraph()
void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
-
+
CustomisedPointsList points;
std::set<string> request;
const Transformation& transformation = visitor.transformation();
@@ -1779,7 +1779,7 @@ void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
box->push_back(PaperPoint(transformation.getMaxX(), 43));
-
+ /*
Text* mint = new Text();
mint->setJustification(MLEFT);
mint->push_back(PaperPoint(transformation.getMaxX()-(w*.95), 46));
@@ -1798,7 +1798,7 @@ void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
maxt->addText("Max: ?" , Colour("navy"), 0.3);
mint->addText( "Min : ?", Colour("navy"), 0.3);
}
-
+ */
vector<string>::iterator style = style_.begin();
vector<int>::iterator thickness = thickness_.begin();
@@ -1834,7 +1834,7 @@ void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
map<string, double>::const_iterator info = (*point)->find(key.str());
int s = info->second;
ostringstream legend;
- legend << "Eps t+ [" << s - 24 << "-" << s <<"h] " ;
+ legend << "t+ [" << s - 24 << "-" << s <<"h] " ;
legend_.push_back(legend.str());
}
@@ -1856,9 +1856,9 @@ void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
for ( vector<BasicGraphicsObject*>::reverse_iterator object = sorter.rbegin(); object != sorter.rend(); ++object)
visitor.push_back(*object);
-// visitor.push_back(box);
-// visitor.push_back(mint);
-// visitor.push_back(maxt);/
+ //visitor.push_back(box);
+ //visitor.push_back(mint);
+ //visitor.push_back(maxt);
}
@@ -1867,6 +1867,13 @@ void CdfGraph::visit(LegendVisitor& legend)
{
+ Polyline* line = new Polyline();
+
+ line->setColour(Colour("black"));
+
+ line->setThickness(4);
+ legend.add(new LineEntry("", line));
+ return;
vector<string>::reverse_iterator style = style_.rbegin();
vector<int>::reverse_iterator thickness = thickness_.rbegin();
@@ -1903,6 +1910,8 @@ void EpsShade::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
std::set<string> request;
const Transformation& transformation = visitor.transformation();
data.customisedPoints(transformation, request, points, true); // we want all the points!
+ double max = transformation.getMaxPCY();
+
if (points.empty()) return;
@@ -2017,6 +2026,7 @@ void EpsShade::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
CustomisedPoint::const_iterator y50 = (*point)->find("50");
CustomisedPoint::const_iterator y25 = (*point)->find("25");
CustomisedPoint::const_iterator y75 = (*point)->find("75");
+
if ( (**point)["tmin"] ) {
tenmin.push_back(PaperPoint(x, y10->second));
nintymin.push_back(PaperPoint(x, y90->second));
@@ -2101,26 +2111,26 @@ void EpsShade::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
- if ( !first->empty() ) visitor.push_back(first);
- if ( !second->empty() ) visitor.push_back(second);
+ if ( !first->empty() ) transformation(*first, visitor);
+ if ( !second->empty() ) transformation(*second, visitor);
- if ( !firstmin->empty() ) visitor.push_back(firstmin);
- if ( !secondmin->empty() ) visitor.push_back(secondmin);
+ if ( !firstmin->empty() ) transformation(*firstmin, visitor);
+ if ( !secondmin->empty() ) transformation(*secondmin, visitor);
- if ( !firstmax->empty() ) visitor.push_back(firstmax);
- if ( !secondmax->empty() ) visitor.push_back(secondmax);
+ if ( !firstmax->empty() ) transformation(*firstmax, visitor);
+ if ( !secondmax->empty() ) transformation(*secondmax, visitor);
- if ( !median->empty() ) visitor.push_back(median);
- if ( !medianmin->empty() ) visitor.push_back(medianmin);
- if ( !medianmax->empty() ) visitor.push_back(medianmax);
+ if ( !median->empty() ) transformation(*median, visitor);
+ if ( !medianmin->empty() ) transformation(*medianmin, visitor);
+ if ( !medianmax->empty() ) transformation(*medianmax, visitor);
- if ( !backbottom->empty() ) visitor.push_back(backbottom);
- if ( !backtop->empty() ) visitor.push_back(backtop);
- if ( !backbottommin->empty() ) visitor.push_back(backbottommin);
- if ( !backtopmin->empty() ) visitor.push_back(backtopmin);
- if ( !backbottommax->empty() ) visitor.push_back(backbottommax);
- if ( !backtopmax->empty() ) visitor.push_back(backtopmax);
+ if ( !backbottom->empty() ) transformation(*backbottom, visitor);
+ if ( !backtop->empty() ) transformation(*backtop, visitor);
+ if ( !backbottommin->empty() ) transformation(*backbottommin, visitor);
+ if ( !backtopmin->empty() ) transformation(*backtopmin, visitor);
+ if ( !backbottommax->empty() ) transformation(*backbottommax, visitor);
+ if ( !backtopmax->empty() ) transformation(*backtopmax, visitor);
}
@@ -2590,14 +2600,14 @@ void EpsPlume::timeserie(Data& data, BasicGraphicsObjectContainer& visitor)
}
if ( line_)
for ( map<string, Polyline* >::const_iterator line = lines.begin(); line != lines.end(); ++line) {
- visitor.push_back(line->second);
+ transformation(*line->second, visitor);
}
if (control_)
- visitor.push_back(control);
+ transformation(*control, visitor);
if (forecast_)
- visitor.push_back(forecast);
+ transformation(*forecast, visitor);
if (median_)
- visitor.push_back(median);
+ transformation(*median, visitor);
}
@@ -2706,7 +2716,7 @@ void EfiGraph::operator()(Data& data, BasicGraphicsObjectContainer& out)
int s = (**point)[step.str()];
ostringstream legend;
- legend << "Eps t+ [" << s - 36 << "-" << s - 12 <<"h] " ;
+ legend << "t+ [" << s - 36 << "-" << s - 12 <<"h] " ;
Polyline* box = new Polyline();
box->setColour(*border_colour_);
diff --git a/src/visualisers/Filter.h b/src/visualisers/Filter.h
index 4df7f43..588bf53 100644
--- a/src/visualisers/Filter.h
+++ b/src/visualisers/Filter.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file Filter.h
\brief Definition of the Template class Filter.
-
+
Magics Team - ECMWF 2004
-
+
Started: Wed 14-Jun-2004
-
+
Changes:
-
+
*/
#ifndef Filter_H
@@ -38,10 +38,10 @@ namespace magics {
class Filter: public vector<UserPoint>
{
-public :
+public :
Filter(MatrixHandler& matrix, int nrows, int ncols);
- virtual ~Filter();
+ virtual ~Filter();
//! Get number of columns of the Mask
int DimensionX () const { return ncols_; }
@@ -50,7 +50,7 @@ public :
int DimensionY () const { return nrows_; }
//! Start the processing of the filters
- virtual bool Process () {}
+ virtual bool Process () { return true; }
protected :
@@ -103,7 +103,7 @@ public:
MinMaxFilter (MatrixHandler& matrix, int nrows, int ncols, int flag=3);
virtual ~MinMaxFilter();
-
+
/*!
Convolutes the filter over the input matrix
Return:
@@ -125,7 +125,7 @@ private:
MinMaxFilter(const MinMaxFilter&);
//! Overloaded << operator to copy - No copy allowed
MinMaxFilter& operator=(const MinMaxFilter&);
-
+
// -- Friends
//! Overloaded << operator to call print().
friend ostream& operator<<(ostream& s,const MinMaxFilter& p)
diff --git a/src/visualisers/HeightTechnique.cc b/src/visualisers/HeightTechnique.cc
index 6dc17ef..2a2ef24 100644
--- a/src/visualisers/HeightTechnique.cc
+++ b/src/visualisers/HeightTechnique.cc
@@ -117,7 +117,7 @@ void CalculateHeightTechnique::set(const HeightTechniqueInterface& interface)
void CalculateHeightTechnique::prepare(LevelSelection& levels)
{
- assert(levels.size() > 1);
+ ASSERT(levels.size() > 1);
heights_.clear();
double step = (levels.size() == 2) ? (max_ - min_) : (max_ - min_) / (levels.size() - 2);
LevelSelection::const_iterator level = levels.begin();
diff --git a/src/visualisers/Histogram.h b/src/visualisers/Histogram.h
index 0ed55ed..42771f5 100644
--- a/src/visualisers/Histogram.h
+++ b/src/visualisers/Histogram.h
@@ -49,7 +49,7 @@ public:
Histogram();
virtual ~Histogram();
- void operator()(Data&, BasicGraphicsObjectContainer& ) { assert(false); }
+ void operator()(Data&, BasicGraphicsObjectContainer& ) { NOTIMP; }
void visit(LegendVisitor& legend);
// Implements the set method ...
void set(const map<string, string>& map ) { HistogramAttributes::set(map); }
diff --git a/src/visualisers/IsoHelper.cc b/src/visualisers/IsoHelper.cc
index 22f328e..853893a 100644
--- a/src/visualisers/IsoHelper.cc
+++ b/src/visualisers/IsoHelper.cc
@@ -30,7 +30,7 @@ void IsoHelper::concatenate_back(vector<Polyline* >& lines, Polyline* poly)
double x = poly->back().x();
double y = poly->back().y();
- vector<Polyline* >::iterator todelete = lines.end();
+
for (vector<Polyline* >::iterator line = lines.begin(); line != lines.end(); ++line) {
if ( *line == poly || (*line)->empty() ) {
continue;
diff --git a/src/visualisers/IsoHighlight.h b/src/visualisers/IsoHighlight.h
index 7eb8801..cafba4f 100644
--- a/src/visualisers/IsoHighlight.h
+++ b/src/visualisers/IsoHighlight.h
@@ -110,7 +110,7 @@ public:
virtual void operator()(Polyline& poly) {
if (poly.empty()) return;
- PaperPoint point = poly.back();
+
//MagLog::dev() << "HIGHTLIGHT?--->" << point << "=" << point.value() << "\n";
const_iterator high = find(poly.back().value());
if ( high == end() ) return;
diff --git a/src/visualisers/IsoPlot.cc b/src/visualisers/IsoPlot.cc
index 2315ce5..438d5af 100644
--- a/src/visualisers/IsoPlot.cc
+++ b/src/visualisers/IsoPlot.cc
@@ -43,7 +43,7 @@
namespace magics {
-
+
static MutexCond producerMutex_;
@@ -141,7 +141,9 @@ public:
return multipleRange;
return singleRange;
}
+ return outOfRange;
+ /// @warning What should be retuned if function arrives here?
}
void push_back(int index, double x1, double y1, double x2, double y2 ){
@@ -177,56 +179,59 @@ public:
}
else {
- // intersect !
- // Create line from 1first
+ // intersect !
+ // Create line from 1first
- typedef boost::geometry::model::polygon<PaperPoint > polygon;
+ typedef boost::geometry::model::polygon<PaperPoint > polygon;
- polygon previous, pts;
+ polygon previous, pts;
- for ( vector<PaperPoint>::iterator pt = points.begin(); pt != points.end(); ++pt ) {
- pts.outer().push_back(*pt);
- }
- pts.outer().push_back(points.front());
- vector<vector<Point> > result;
- helper->second->computePolygonLines(result);
- assert( result.size() == 1);
- for ( vector<Point>::iterator pt = result.front().begin(); pt != result.front().end(); ++pt ) {
- previous.outer().push_back(PaperPoint(pt->x_, pt->y_));
- }
+ for ( vector<PaperPoint>::iterator pt = points.begin(); pt != points.end(); ++pt ) {
+ pts.outer().push_back(*pt);
+ }
+ pts.outer().push_back(points.front());
+ vector<vector<Point> > result;
+ helper->second->computePolygonLines(result);
+ ASSERT( result.size() == 1);
+ for ( vector<Point>::iterator pt = result.front().begin(); pt != result.front().end(); ++pt ) {
+ previous.outer().push_back(PaperPoint(pt->x_, pt->y_));
+ }
- helper_[index] = new SegmentJoiner();
+ helper_[index] = new SegmentJoiner();
- std::vector<polygon > output;
+ std::vector<polygon > output;
+ try {
+ boost::geometry::intersection(previous, pts, output);
- boost::geometry::intersection(previous, pts, output);
+ if (output.size() == 1){
+ vector<PaperPoint> xx;
+ for ( vector<PaperPoint>::iterator pt = output.front().outer().begin(); pt != output.front().outer().end(); ++pt ) {
+ xx.push_back(*pt);
+ }
+ push_back(index, xx);
- if (output.size() == 1){
- vector<PaperPoint> xx;
- for ( vector<PaperPoint>::iterator pt = output.front().outer().begin(); pt != output.front().outer().end(); ++pt ) {
- xx.push_back(*pt);
- }
+ }
+ else
+ {
- push_back(index, xx);
+ boost::geometry::union_(pts, previous, output);
+ if (output.size() == 1){
+ push_back(index, output.front().outer());
+ }
+ else
+ push_back(index, previous.outer());
- }
- else
- {
-
- boost::geometry::union_(pts, previous, output);
- if (output.size() == 1){
- push_back(index, output.front().outer());
- }
- else
- push_back(index, previous.outer());
-
- }
+ }
+ }
+ catch (...) {
+ // ignore
+ }
}
@@ -335,8 +340,8 @@ public:
default:
split();
if (empty()) {
- assert( row1_ == row2_);
- assert( column1_ == column2_);
+ ASSERT( row1_ == row2_);
+ ASSERT( column1_ == column2_);
owner.isoline(*(*parent_)(row1_, column1_), this);
}
@@ -380,10 +385,11 @@ public:
list<vector<Point> > holes;
SegmentJoiner& joiner = *index->second;
- //if (index->first == 4)
- //joiner.print();
+
joiner.computePolygonLines(result);
Polyline* poly = 0;
+ if ( result.empty() )
+ continue;
bool reverse = joiner.isHole(result.front());
for (vector<vector<Point> >::iterator j = result.begin() ; j != result.end(); ++j) {
@@ -589,7 +595,7 @@ void IsoPlot::isoline(Cell& cell, CellBox* parent) const
if ( !parent ) // NO Shading == Nothing to do!
return;
else {
-
+
int index = shading_->shadingIndex(cell.value(0));
vector<PaperPoint> points;
@@ -1185,7 +1191,7 @@ void IsoPlot::isoline(MatrixHandler& data, BasicGraphicsObjectContainer& parent)
{
const Transformation& transformation = parent.transformation();
- Polyline& x = transformation.getPCBoundingBox();
+
@@ -1245,7 +1251,7 @@ void IsoPlot::isoline(MatrixHandler& data, BasicGraphicsObjectContainer& parent)
CellBox view(array);
threads_ = (needIsolines()) ? 4: 0;
- //threads_ = 1;
+ //threads_ = 1;
vector<IsoHelper*> consumers_;
vector<IsoProducer* > producers_;
@@ -1271,7 +1277,7 @@ void IsoPlot::isoline(MatrixHandler& data, BasicGraphicsObjectContainer& parent)
int c = 0;
VectorOfPointers<vector<IsoProducerData*> > datas;
for ( int i = 0; i < view.size(); i++)
- //int i = 0;
+ //int i = 1;
{
IsoProducerData* data = new IsoProducerData(shading_->shadingMode(), *this, *(view[i]));
@@ -1369,7 +1375,7 @@ void IsoPlot::isoline(MatrixHandler& data, BasicGraphicsObjectContainer& parent)
for (vector<Polyline* >::const_iterator poly = (*lines)->begin(); poly != (*lines)->end(); ++poly)
{
if ( (*poly)->empty() ) continue;
- double level = (*poly)->front().value();
+
if ( !rainbow_ ) {
@@ -1619,7 +1625,7 @@ void IsoPlot::visit(Data& data, PointsHandler& points, HistoVisitor& visitor)
}
CellArray::CellArray(MatrixHandler& data, IntervalMap<int>& range, const Transformation& transformation, int width, int height, float resol, const string& technique) :
- data_(data), rangeFinder_(range)
+ rangeFinder_(range),data_(data)
{
Timer timer("CellArray", "CellArray");
int r = height/resol;
@@ -1703,7 +1709,7 @@ CellArray::CellArray(MatrixHandler& data, IntervalMap<int>& range, const Transfo
}
-CellArray::CellArray(MatrixHandler& data, IntervalMap<int>& range) : data_(data), rangeFinder_(range)
+CellArray::CellArray(MatrixHandler& data, IntervalMap<int>& range) : rangeFinder_(range), data_(data)
{
}
@@ -1787,8 +1793,8 @@ GridCell::GridCell(const CellArray& data, int row, int column, const Transformat
count++;
for (int i = 0; i < 4; i++) {
- double lon = columns_[i];
- double lat = rows_[i];
+
+
transformation.fast_reproject(columns_[i], rows_[i]);
if ( columns_[i] < minx ) {
diff --git a/src/visualisers/IsoPlot.h b/src/visualisers/IsoPlot.h
index 0ce9645..fa60a11 100644
--- a/src/visualisers/IsoPlot.h
+++ b/src/visualisers/IsoPlot.h
@@ -175,7 +175,7 @@ public:
const pair<int, int>& index(int i) {
- assert(i < 4);
+ ASSERT(i < 4);
return indexes_[i];
}
@@ -268,7 +268,7 @@ public:
return columns_[i];
}
const pair<int, int>& index(int i) {
- assert(i < 4);
+ ASSERT(i < 4);
return indexes_[i];
}
diff --git a/src/visualisers/LabelPlotting.h b/src/visualisers/LabelPlotting.h
index fc6eb5a..4583d4f 100644
--- a/src/visualisers/LabelPlotting.h
+++ b/src/visualisers/LabelPlotting.h
@@ -134,11 +134,10 @@ public:
void label(Transformation&);
void add(Text* text) const
{
- MagFont font;
+ MagFont font(font_, font_style_, height_);
font.colour(*colour_);
- font.size(height_);
text->setFont(font);
- text->setBlanking(true);
+ text->setBlanking(blanking_);
layer_->push_back(text);
}
diff --git a/src/visualisers/LevelSelection.cc b/src/visualisers/LevelSelection.cc
index 98ca7db..02de7e0 100644
--- a/src/visualisers/LevelSelection.cc
+++ b/src/visualisers/LevelSelection.cc
@@ -49,13 +49,14 @@ void LevelSelection::print(ostream& out) const
doublearray::print(out);
out << "]";
}
+
void LevelSelection::thinLevels(int frequency, vector<double>& out) const
{
if ( empty() ) return;
double ref = reference(frequency);
int count = 0;
- // Fisrt is the reference in the levels list?
+ // First is the reference in the levels list?
const_iterator reflev = find(begin(), end(), ref);
if ( reflev == end() )
reflev = begin();
@@ -66,22 +67,20 @@ void LevelSelection::thinLevels(int frequency, vector<double>& out) const
count++;
}
-// now we have to reverse!
+ // now we have to reverse!
const_reverse_iterator rlevel = rbegin();
while ( rlevel != rend() ) {
-
if (*rlevel == *reflev )
break;
++rlevel;
- }
+ }
count=1;
++rlevel;
- for (rlevel; rlevel != rend(); ++rlevel) {
+ for (; rlevel != rend(); ++rlevel) {
if ( count%frequency == 0 ) {
out.push_back(*rlevel);
-
}
count++;
}
diff --git a/src/visualisers/MarkerShadingTechnique.cc b/src/visualisers/MarkerShadingTechnique.cc
index 2a48eaa..80f015e 100644
--- a/src/visualisers/MarkerShadingTechnique.cc
+++ b/src/visualisers/MarkerShadingTechnique.cc
@@ -121,14 +121,26 @@ bool MarkerShadingTechnique::prepare(const LevelSelection& levels, const ColourT
if ( height_.empty() ) {
height_.push_back(0.2);
}
+
+ if ( marker_.empty() ) {
+ marker_.push_back(18);
+ }
if ( marker_.empty() ) {
marker_.push_back(18);
}
+
+ if ( magCompare(type_, "index") ) {
+ symbol_.clear();
+ }
+ if ( symbol_.empty() ) {
+ for ( intarray::iterator marker = marker_.begin(); marker != marker_.end(); ++marker )
+ symbol_.push_back(Symbol::convert(*marker));
+ }
// Prepare the table ...
stringarray::iterator colour = colour_.begin();
doublearray::iterator height = height_.begin();
- intarray::iterator marker = marker_.begin();
+ stringarray::iterator name = symbol_.begin();
for (unsigned int i = 0; i < levels.size() -1; i++)
@@ -137,11 +149,11 @@ bool MarkerShadingTechnique::prepare(const LevelSelection& levels, const ColourT
Symbol* symbol = new Symbol();
symbol->setColour(Colour(*colour));
- symbol->setMarker(*marker);
+ symbol->setSymbol(*name);
symbol->setHeight(*height);
Symbol* legend = new Symbol();
legend->setColour(Colour(*colour));
- legend->setMarker(*marker);
+ legend->setSymbol(*name);
legend->setHeight(*height);
map_[Interval(levels[i], levels[i+1])] = symbol;
legend_[Interval(levels[i], levels[i+1])] = legend;
@@ -155,9 +167,9 @@ bool MarkerShadingTechnique::prepare(const LevelSelection& levels, const ColourT
MagLog::warning() << "MarkerShading --> not enough heights defined!\n";
height = height_.begin();
}
- if ( ++marker == marker_.end()) {
+ if ( ++name == symbol_.end()) {
MagLog::warning() << "MarkerShading --> not enough markers defined!\n";
- marker = marker_.begin();
+ name = symbol_.begin();
}
}
}
diff --git a/src/visualisers/ObsItem.h b/src/visualisers/ObsItem.h
index e87c0f9..37c0dcc 100644
--- a/src/visualisers/ObsItem.h
+++ b/src/visualisers/ObsItem.h
@@ -4,7 +4,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +18,13 @@
/*! \file ObsItem.h
\brief Definition of the Template class ObsItem.
-
+
Magics Team - ECMWF 2005
-
+
Started: Wed 18-May-2005
-
+
Changes:
-
+
*/
#ifndef ObsItem_H
@@ -49,18 +49,18 @@ class ObsItem {
public:
ObsItem(): owner_(0) {}
virtual ~ObsItem() {}
-
+
virtual void set(const map<string, string>&) {}
- virtual void operator()(CustomisedPoint&, ComplexSymbol&) const {}
+ virtual void operator()(CustomisedPoint&, ComplexSymbol&) const {}
virtual void visit(std::set<string>&) {}
-
+
string find(const map<string, string>& def, const string& keyword, const string& defaut = "")
{
map<string, string>::const_iterator val = def.find(keyword);
return ( val != def.end() ) ? val->second : defaut;
}
- ObsPlotting* set(const ObsPlotting* owner) const { owner_ = owner; }
+ void set(const ObsPlotting* owner) const { owner_ = owner; }
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
@@ -82,12 +82,12 @@ private:
};
template<>
-class MagTranslator<string, ObsItem> {
+class MagTranslator<string, ObsItem> {
public:
ObsItem* operator()(const string& val )
{
return SimpleObjectMaker<ObsItem>::create(val);
- }
+ }
ObsItem* magics(const string& param)
{
diff --git a/src/visualisers/ObsItemFamily.cc b/src/visualisers/ObsItemFamily.cc
index 81be867..d8373d9 100644
--- a/src/visualisers/ObsItemFamily.cc
+++ b/src/visualisers/ObsItemFamily.cc
@@ -79,7 +79,7 @@ void ObsWind::operator()( CustomisedPoint& point, ComplexSymbol& symbol) const
MagLog::debug() << "OBS ITEM - ObsWind - Lon/Lat: "<<point.longitude()<<" / "<<point.latitude()
<< "\n\twind_speed: " << point[speed_]
<< "\n\twind_direction: " << point[direction_]
- << "\n\tcloud amount: " << point["cloud_amount"]<<" -> "<<origin << std::endl;
+ << "\n\tcloud amount: " << point["total_cloud"]<<" -> "<<origin << std::endl;
flag->setOriginHeight(owner_->ring_size_);
@@ -111,10 +111,15 @@ void ObsCloudAndWind::setOrigins()
origins_[6] = "N_6";
origins_[7] = "N_7";
origins_[8] = "N_8";
+ origins_[59] = "N_9";
+ origins_[60] = "N_9";
+ origins_[61] = "N_9";
+ origins_[62] = "N_9";
}
void ObsCloudAndWind::operator()( CustomisedPoint& point, ComplexSymbol& symbol) const
{
+
if (!owner_->wind_visible_) return;
Colour colour = owner_->wind_colour_->automatic() ? *owner_->colour_ : *owner_->wind_colour_;
@@ -133,16 +138,28 @@ void ObsCloudAndWind::operator()( CustomisedPoint& point, ComplexSymbol& symbol)
FlagItem* flag = new FlagItem();
flag->setColour(colour);
- flag->length(owner_->size_ * 2.5); // Size to be adjusted later!
+ flag->length(owner_->size_*2.5); // Size to be adjusted later!
+
- map<int, string>::const_iterator marker = origins_.find(int(point["cloud_amount"]));
- const string origin = ( marker != origins_.end()) ? marker->second : "magics_13";
+ int total_cloud = maground((point["total_cloud"]/100.)*8);
+ MagLog::debug() << "total_cloud-->" << point["total_cloud"] << "--->" << total_cloud << endl;
+ map<int, string>::const_iterator marker = origins_.find(total_cloud);
+ string origin;
+ if ( marker != origins_.end() )
+ origin = marker->second;
+ else {
+
+ // here we check that the sky is not obscured
+ marker = origins_.find(int(point["low_cloud"]));
+ origin = marker != origins_.end() ? marker->second : "magics_13";
+
+ }
MagLog::debug() << "OBS ITEM - ObsWind - Lon/Lat: "<<point.longitude()<<" / "<<point.latitude()
<< "\n\twind_speed: " << point["wind_speed"]
<< "\n\twind_direction: " << point["wind_direction"]
- << "\n\tcloud amount: " << point["cloud_amount"]<<" -> "<<origin << std::endl;
+ << "\n\tcloud amount: " << point["total_cloud"]<< "--->" << total_cloud << "--->" << origin << std::endl;
flag->setOriginHeight(owner_->ring_size_);
flag->setOriginMarker(origin);
@@ -250,7 +267,7 @@ void ObsPressureTendency::operator()(CustomisedPoint& point, ComplexSymbol& symb
object->y(row_);
ostringstream os;
- if(value->second>0) os << setw(2) << setfill('0') << value->second * .1;
+ if(value->second>=0) os << setw(2) << setfill('0') << value->second * .1;
else os << "-" << setw(2) << setfill('0') << value->second * -.1;
// The Pressure tendancy is red if negative!
@@ -276,7 +293,7 @@ void ObsPressureTendency::operator()(CustomisedPoint& point, ComplexSymbol& symb
MagLog::debug() << "\tPressure tendency--->" << oss.str() << "\n";
- tendancy->height(owner_->size_);
+ tendancy->height(owner_->size_*0.2); // A bit too big !
symbol.add(tendancy);
}
@@ -295,17 +312,17 @@ void ObsDewPoint::operator()(CustomisedPoint& point, ComplexSymbol& symbol) con
if ( value == point.end() ) return;
TextItem* object = new TextItem();
MagFont font("sansserif");
- Colour colour = owner_->pressure_tendency_colour_->automatic() ? *owner_->colour_ : *owner_->pressure_tendency_colour_;
+ Colour colour = owner_->dewpoint_colour_->automatic() ? *owner_->colour_ : *owner_->dewpoint_colour_;
font.colour(colour);
font.size(owner_->size_);
object->x(column_);
object->y(row_);
// The temperature is displayed in Celsius.
- const double tempe = maground(value->second-273.25);
-#ifdef OBS_DEBUG_
+ const double tempe = maground(value->second-273.15);
+
MagLog::debug() << "\tDewPoint--->" << point["dewpoint_2meters"] << " = " << tempe << "\n";
-#endif
+
object->text(tostring(tempe));
object->font(font);
//object->setJustification(MCENTRE);
@@ -366,25 +383,79 @@ void ObsPresentWeather::visit(std::set<string>& tokens)
}
+static map<int, string> presentweather;
void ObsPresentWeather::operator()(CustomisedPoint& point, ComplexSymbol& symbol) const
{
if (!owner_->present_ww_visible_) return;
+ if ( presentweather.empty() ) {
+ presentweather[100] = "ww_00";
+ presentweather[101] = "ww_01";
+ presentweather[102] = "ww_02";
+ presentweather[103] = "ww_03";
+ presentweather[104] = "ww_04";
+ presentweather[110] = "ww_10";
+ presentweather[120] = "ww_45";
+ presentweather[121] = "ww_60";
+ presentweather[122] = "ww_20";
+ presentweather[123] = "ww_61";
+ presentweather[130] = "ww_45"; // Fog
+ presentweather[131] = "ww_41";
+ presentweather[132] = "ww_42";
+ presentweather[133] = "ww_44";
+ presentweather[134] = "ww_46";
+ presentweather[140] = "ww_60";
+ presentweather[141] = "ww_61";
+ presentweather[150] = "ww_51";
+ presentweather[151] = "ww_51";
+ presentweather[152] = "ww_52";
+ presentweather[153] = "ww_55";
+ presentweather[157] = "ww_58";
+ presentweather[158] = "ww_59";
+ presentweather[160] = "ww_60";
+ presentweather[161] = "ww_61";
+ presentweather[162] = "ww_62";
+ presentweather[163] = "ww_65";
+ presentweather[180] = "ww_80";
+ presentweather[181] = "ww_80";
+ presentweather[182] = "ww_81";
+ presentweather[183] = "ww_81";
+ presentweather[189] = "ww_89";
+ }
CustomisedPoint::const_iterator value = point.find("present_weather");
if ( value == point.end() ) return;
+ if ( value->second < 4 )
+ return;
+ if ( value->second > 500 )
+ return;
+ string ww;
+
+ if ( value->second < 100 ) {
+ ostringstream os;
+ os << "ww_" << setw(2) << setfill('0') << value->second;
+ ww = os.str();
+ }
+ else {
+ map<int, string>::iterator w = presentweather.find(value->second);
+ if ( w == presentweather.end() ) {
+ MagLog::warning() << "Present Weather " << value->second << " is not recognised yet, pease conatct the magics team " << endl;
+ }
+ else
+ ww = w->second;
+ }
+
+ if ( ww.empty() )
+ return;
SymbolItem* object = new SymbolItem();
object->x(column_);
object->y(row_);
Colour colour = owner_->present_ww_colour_->automatic() ? *owner_->colour_ : *owner_->present_ww_colour_;
object->colour(colour);
- //object->setFont("sansserif");
- ostringstream os;
- os << "ww_" << setw(2) << setfill('0') << value->second;
- object->symbol(os.str());
- MagLog::debug() << "\tPresent Weather--->" << os.str() << " in " << colour << "\n";
+ object->symbol(ww);
+ MagLog::debug() << "\tPresent Weather--->" << ww << " in " << colour << "\n";
//time->setJustification(MRIGHT);
object->height(owner_->size_);
symbol.add(object);
@@ -408,10 +479,10 @@ void ObsTemperature::operator()(CustomisedPoint& point, ComplexSymbol& symbol)
object->y(row_);
// The temperature is displayed in Celsius.
- double tempe = maground(value->second-273.25);
-#ifdef OBS_DEBUG_
+ double tempe = maground(value->second-273.15);
+
MagLog::debug() << "\tTemperature: " << tempe << " from "<<value->second<<"\n";
-#endif
+
object->text(tostring(tempe));
//object->setJustification(MCENTRE);
@@ -431,9 +502,9 @@ void ObsTimePlot::operator()(CustomisedPoint& point, ComplexSymbol& symbol) con
if (!owner_->time_plot_visible_) return;
CustomisedPoint::const_iterator value = point.find("time");
if ( value == point.end() ) return;
-#ifdef OBS_DEBUG_
+
MagLog::debug() << "\tTimePlot: " << value->second << "at[" << column_ << ", " << row_ << "]" << endl;
-#endif
+
Colour colour = owner_->time_plot_colour_->automatic() ? *owner_->colour_ : *owner_->time_plot_colour_;
@@ -465,9 +536,8 @@ void ObsHeight::operator()(CustomisedPoint& point, ComplexSymbol& symbol) const
CustomisedPoint::const_iterator value = point.find("geopotential");
if ( value == point.end() ) return;
double geop = maground(value->second/98.1);
-#ifdef OBS_DEBUG_
+
MagLog::debug() << "\tGeopotential: " << geop << "at[" << column_ << ", " << row_ << "]" << endl;
-#endif
Colour colour = owner_->height_colour_->automatic() ? *owner_->colour_ : *owner_->height_colour_;
TextItem* height = new TextItem();
MagFont font("sansserif");
@@ -553,49 +623,96 @@ void ObsPastWeather::visit(std::set<string>& tokens)
tokens.insert("past_weather_1");
tokens.insert("past_weather_2");
}
-
+/*
+WMO table 020004: PAST WEATHER (1)
+
+code meaning
+---- -------
+ 0 CLOUD COVERING 1/2 OR LESS OF THE SKY THROUGHOUT THE APPROPRIATE PERIOD
+ 1 CLOUD COVERING MORE THAN 1/2 OF THE SKY DURING PART OF THE APPROPRIATE
+ PERIOD AND COVERING 1/2 OR LESS DURING PART OF THE PERIOD
+ 2 CLOUD COVERING MORE THAN 1/2 OF THE SKY THROUGHOUT THE APPROPRIATE PERIOD
+ 3 SANSTORM, DUSTSTORM OR BLOWING SNOW
+ 4 FOG OR ICE OR THICK HAZE
+ 5 DRIZZLE
+ 6 RAIN
+ 7 SNOW, OR RAIN AND SNOW MIXED
+ 8 SHOWER(S)
+ 9 THUNDERSTORM(S) WITH OR WITHOUT PRECIPITATION
+ 10 NO SIGNIFICANT WEATHER OBSERVED
+ 11 VISIBILITY REDUCED
+ 12 BLOWING PHENOMENA, VISIBILITY REDUCED
+ 13 FOG
+ 14 PRECIPITATION
+ 15 DRIZZLE
+ 16 RAIN
+ 17 SNOW OR ICE PELLETS
+ 18 SHOWERS OR INTERMITTENT PRECIPITATION
+ 19 THUNDERSTORM
+ 31 MISSING VALUE
+*/
+static map<int, string> pastweather;
void ObsPastWeather::operator()(CustomisedPoint& point, ComplexSymbol& symbol) const
{
+ if ( pastweather.empty() ) {
+ pastweather[3] = "W_3";
+ pastweather[4] = "W_4";
+ pastweather[5] = "W_5";
+ pastweather[6] = "W_6";
+ pastweather[7] = "W_6";
+ pastweather[8] = "W_8";
+ pastweather[9] = "W_9";
+ pastweather[11] = "W_4";
+ pastweather[12] = "W_4";
+ pastweather[13] = "W_4";
+ pastweather[14] = "W_6";
+ pastweather[15] = "W_5";
+ pastweather[17] = "W_7";
+ pastweather[18] = "W_8";
+ pastweather[19] = "W_9";
+ }
+
if (!owner_->past_ww_visible_) return;
CustomisedPoint::const_iterator value = point.find("past_weather_1");
if ( value == point.end() ) return;
Colour colour = owner_->past_ww_colour_->automatic() ? *owner_->colour_ : *owner_->past_ww_colour_;
- if(value->second > 2)
+ map<int, string>::iterator ww = pastweather.find(value->second);
+
+ if( ww != pastweather.end() )
{
SymbolItem* object = new SymbolItem();
object->x(column_);
object->y(row_);
object->colour(colour);
- ostringstream os;
- os << "W_" << value->second;
- object->symbol(os.str());
-#ifdef OBS_DEBUG_
- MagLog::debug() << "\tPast Weather 1-> " << os.str() << "\n";
-#endif
+
+ object->symbol(ww->second);
+
+ MagLog::debug() << "\tPast Weather 1-> " << ww->second << "\n";
+
object->height(owner_->size_);
symbol.add(object);
-
+ }
//second past weather
- value = point.find("past_weather_2");
- if ( value == point.end() ) return;
- if(value->second > 2)
+ value = point.find("past_weather_2");
+ if ( value == point.end() ) return;
+ ww = pastweather.find(value->second);
+ if( ww != pastweather.end())
{
SymbolItem* object2 = new SymbolItem();
object2->x(column_*2);
object2->y(row_);
object2->colour(colour);
- ostringstream os2;
- os2 << "W_" << value->second;
- object2->symbol(os2.str());
-#ifdef OBS_DEBUG_
- MagLog::debug() << "\tPast Weather 2-> " << os2.str() << "\n";
-#endif
+
+ object2->symbol(ww->second);
+
+ MagLog::debug() << "\tPast Weather 2-> " << ww->second << "\n";
+
object2->height(owner_->size_);
symbol.add(object2);
}
- }
+
}
///////////////////////////////////////////////////////////////////////////////////
@@ -615,28 +732,64 @@ void ObsCloud::visit(std::set<string>& tokens)
if ( owner_->high_ ) tokens.insert("high_cloud");
}
-
+
+
+static map<int, string> clouds_;
+
void ObsCloud::operator()(CustomisedPoint& point, ComplexSymbol& symbol) const
{
+ if ( clouds_.empty() ) {
+ clouds_[1] = "CH_1"; // CIRROCUMULUS (CC)
+ clouds_[2] = "CH_2"; // 2 2 CIRROSTRATUS (CS)
+ clouds_[3] = "CH_3"; // 3 3 ALTOCUMULUS (AC)
+ clouds_[4] = "CH_4"; // 4 4 ALTOSTRATUS (AS)
+ clouds_[5] = "CH_5"; // 5 5 NIMBOSTRATUS (NS)
+ clouds_[6] = "CH_6"; // 6 6 STRATOCUMULUS (SC)
+ clouds_[7] = "CH_7"; // 7 7 STRATUS (ST)
+ clouds_[8] = "CH_8"; // 8 8 CUMULUS (CU)
+ clouds_[9] = "CH_0"; // 9 9 CUMULONIMBUS (CB)
+ //10 10 NO CH CLOUDS
+ clouds_[11] = "CH_1"; // 11 11 CIRRUS FIBRATUS, SOMETIMES UNCINUS, NOT PROGRESSIVELY INVADING THE SKY
+ clouds_[12] = "CH_2"; //12 12 CIRRUS SPISSATUS, IN PATCHES OR ENTANGLED SHEAVES, WHICH USUALLY DO NOT INCREASE AND SOMETIMES SEEM TO BE THE REMAINS OF THE UPPER PART OF A CUMULONIMBUS; OR CIRRUS CASTELLANUS OR FLOCCUS
+ clouds_[13] = "CH_3"; //13 13 CIRRUS SPISSATUS CUMULONIMBOGENITUS
+ clouds_[14] = "CH_4"; // 14 14 CIRRUS UNCINUS OR FIBRATUS, OR BOTH, PROGRESSIVELY INVADING THE SKY; THEY GENERALLY THICKEN AS A WHOLE
+ clouds_[15] = "CH_5"; //15 15 CIRRUS (OFTEN IN BANDS) AND CIRROSTRATUS, OR CIRROSTRATUS ALONE, PROGRESSIVELY INVADING THE SKY; THEY GENERALLY THICKEN AS A WHOLE, BUT THE CONTINUOUS VEIL DOES NOT REACH 45 DEGREES ABOVE THE HORIZON
+ clouds_[16] = "CH_6"; //16 16 CIRRUS (OFTEN IN BANDS) AND CIRROSTRATUS, OR CIRROSTRATUS ALONE, PROGRESSIVELY INVADING THE SKY; THEY GENERALLY THICKEN AS A WHOLE; THE CONTINUOUS VEIL EXTENDS MORE THAN 45 DEGREES ABOVE THE HORIZON, WITHOUT THE SKY BEING TOTALLY COVERED
+ clouds_[17] = "CH_7"; //17 17 CIRROSTRATUS COVERING THE WHOLE SKY
+ clouds_[18] = "CH_8"; //18 18 CIRROSTRATUS NOT PROGRESSIVELY INVADING THE SKY AND NOT ENTIRELY COVERING IT
+ clouds_[19] = "CH_9"; //19 19 CIRROCUMULUS ALONE, OR CIRROCUMULUS PREDOMINANT AMONG THE CH CLOUDS
+ //20 20 NO CM CLOUDS
+ clouds_[21] = "CM_1"; //21 21 ALTOSTRATUS TRANSLUCIDUS
+ clouds_[22] = "CM_2"; //22 22 ALTOSTRATUS OPACUS OR NIMBOSTRATUS
+ clouds_[23] = "CM_3"; //23 23 ALTOCUMULUS TRANSLUCIDUS AT A SINGLE LEVEL
+ clouds_[24] = "CM_4"; //24 24 PATCHES (OFTEN LENTICULAR) OF ALTOCUMULUS TRANSLUCIDUS, CONTINUALLY CHANGING AND OCCURRING AT ONE OR MORE LEVELS
+ clouds_[25] = "CM_5"; //25 25 ALTOCUMULUS TRANSLUCIDUS IN BANDS, OR ONE OR MORE LAYERS OF ALTOCUMULUS TRANSLUCIDUS OR OPACUS, PROGRESSIVELY INVADING THE SKY; THESE ALTOCUMULUS CLOUDS GENERALLY THICKEN AS A WHOLE
+ clouds_[26] = "CM_6"; //26 26 ALTOCUMULUS CUMULOGENITUS (OR CUMULONIMBOGENITUS)
+ clouds_[27] = "CM_7"; //27 27 ALTOCUMULUS TRANSLUCIDUS OR OPACUS IN TWO OR MORE LAYERS, OR ALTOCUMULUS OPACUS IN A SINGLE LAYER, NOT PROGRESSIVELY INVADING THE SKY, OR ALTOCUMULUS WITH ALTOSTRATUS OR NIMBOSTRATUS
+ clouds_[28] = "CM_8"; // 28 28 ALTOCUMULUS CASTELLANUS OR FLOCCUS
+ clouds_[29] = "CM_9"; //29 29 ALTOCUMULUS OF A CHAOTIC SKY, GENERALLY AT SEVERAL LEVELS
+ //30 30 NO CL CLOUDS
+ clouds_[31] = "CL_1"; //31 31 CUMULUS HUMILIS OR CUMULUS FRACTUS OTHER THAN OF BAD WEATHER,* OR BOTH
+ clouds_[32] = "CL_2"; //32 32 CUMULUS MEDIOCRIS OR CONGESTUS, TOWERING CUMULUS (TCU), WITH OR WITHOUT CUMULUS OF SPECIES FRACTUS OR HUMILIS OR STRATOCUMULUS, ALL HAVING THEIR BASES AT THE SAME LEVEL
+ clouds_[33] = "CL_3"; //33 33 CUMULONIMBUS CALVUS, WITH OR WITHOUT CUMULUS, STRATOCUMULUS OR STRATUS
+ clouds_[34] = "CL_4"; //34 34 STRATOCUMULUS CUMULOGENITUS
+ clouds_[35] = "CL_5"; //35 35 STRATOCUMULUS OTHER THAN STRATOCUMULUS CUMULOGENITUS
+ clouds_[36] = "CL_6"; //36 36 STRATUS NEBULOSUS OR STRATUS FRACTUS OTHER THAN OF BAD WEATHER,* OR BOTH
+ clouds_[37] = "CL_7"; //37 37 STRATUS FRACTUS OR CUMULUS FRACTUS OF BAD WEATHER,* OR BOTH (PANNUS), USUALLY BELOW ALTOSTRATUS OR NIMBOSTRATUS
+ clouds_[38] = "CL_8"; //38 38 CUMULUS AND STRATOCUMULUS OTHER THAN STRATOCUMULUS CUMULOGENITUS, WITH BASES AT DIFFERENT LEVELS
+ clouds_[39] = "CL_9"; //39 39 CUMULONIMBUS CAPILLATUS (OFTEN WITH AN ANVIL), WITH OR WITHOUT CUMULONIMBUS CALVUS, CUMULUS, STRATOCUMULUS, STRATUS OR PANNUS
+ //0 40 CH
+ //41 41 CM
+ //42 42 CL
+ //59 59 CLOUD NOT VISIBLE OWING TO DARKNESS, FOG, DUSTSTORM, SANDSTORM, OR OTHER ANALOGOUS PHENOMENA
+ //60 60 CH CLOUDS INVISIBLE OWING TO DARKNESS, FOG, BLOWING DUST OR SAND, OR OTHER SIMILAR PHENOMENA, OR BECAUSE OF A CONTINUOUS LAYER OF LOWER CLOUDS
+ //61 61 CM CLOUDS INVISIBLE OWING TO DARKNESS, FOG, BLOWING DUST OR SAND, OR OTHER SIMILAR PHENOMENA, OR BECAUSE OF CONTINUOUS LAYER OF LOWER CLOUDS
+ //62 62 CL CLOUDS INVISIBLE OWING TO DARKNESS, FOG, BLOWING DUST OR SAND, OR OTHER SIMILAR PHENOMENA
+ }
+
if (!owner_->cloud_visible_) return;
symbol.setHeight(owner_->size_);
- CustomisedPoint::const_iterator value = point.find("low_cloud");
- if ( value != point.end() )
- {
- SymbolItem* cloud = new SymbolItem();
- cloud->x(lowColumn_);
- cloud->y(lowRow_);
- cloud->colour(*owner_->low_colour_);
- ostringstream oss;
- int type = int(value->second - (int (value->second/10) *10));
- oss << "CL_" << type;
- cloud->symbol(oss.str());
-
- MagLog::debug() << "\tLow Cloud--->" << oss.str() << "\n";
-
- cloud->height(owner_->ring_size_);
- symbol.add(cloud);
- }
+
CustomisedPoint::const_iterator height = point.find("low_cloud_height");
CustomisedPoint::const_iterator nebul = point.find("low_cloud_nebulosity");
@@ -672,53 +825,69 @@ void ObsCloud::operator()(CustomisedPoint& point, ComplexSymbol& symbol) const
MagFont font;
font.name("sansserif");
font.colour(*owner_->low_colour_);
- font.size(owner_->size_*.6);
-#ifdef OBS_DEBUG_
- MagLog::debug() << "\tLow Cloud Nebulosity--->" << value->second << "\n";
-#endif
+ font.size(owner_->size_* 0.8);
+
+ MagLog::debug() << "\tLow Cloud--->" << nh.str() << "\n";
object->text(nh.str());
object->font(font);
symbol.add(object);
}
- value = point.find("medium_cloud");
- if ( value != point.end() )
+ CustomisedPoint::const_iterator value = point.find("low_cloud");
+ if ( value != point.end() ) {
+ map<int, string>::iterator low = clouds_.find(value->second);
+ if ( low != clouds_.end() )
+ {
+ SymbolItem* cloud = new SymbolItem();
+ cloud->x(lowColumn_);
+ cloud->y(lowRow_);
+ cloud->colour(*owner_->low_colour_);
+
+ cloud->symbol(low->second);
+
+ MagLog::debug() << "\tLow Cloud--->" << value->second << "-->" << low->second << "\n";
+
+ cloud->height(owner_->size_);
+ symbol.add(cloud);
+ }
+ }
value = point.find("medium_cloud");
- if ( value != point.end() )
- {
- SymbolItem* cloud = new SymbolItem();
- cloud->x(mediumColumn_);
- cloud->y(mediumRow_);
-
- cloud->colour(*owner_->medium_colour_);
- ostringstream oss;
- int type = int(value->second - (int (value->second/10.) *10));
- oss << "CM_" << type;
- cloud->symbol(oss.str());
-
- MagLog::debug() << "\tMedium Cloud--->" <<value->second<<" > "<< oss.str() << "\n";
-
- cloud->height(owner_->size_);
- symbol.add(cloud);
+ if ( value != point.end() ) {
+ map<int, string>::iterator medium = clouds_.find(value->second);
+
+ if ( medium != clouds_.end() )
+ {
+ SymbolItem* cloud = new SymbolItem();
+ cloud->x(mediumColumn_);
+ cloud->y(mediumRow_);
+ cloud->colour(*owner_->medium_colour_);
+ cloud->symbol(medium->second);
+
+ MagLog::debug() << "\tMedium Cloud--->" << value->second<< " --> "<< medium->second << "\n";
+
+ cloud->height(owner_->size_);
+ symbol.add(cloud);
+ }
}
value = point.find("high_cloud");
- if ( value != point.end() )
- {
- SymbolItem* cloud = new SymbolItem();
- cloud->x(highColumn_);
- cloud->y(highRow_);
- cloud->colour(*owner_->high_colour_);
- ostringstream oss;
- int type = int(value->second - (int (value->second/10) *10));
- oss << "CH_" << type;
- cloud->symbol(oss.str());
-
- MagLog::debug() << "\tHigh Cloud--->" << oss.str() << "\n";
-
- cloud->height(owner_->size_);
- symbol.add(cloud);
+ if ( value != point.end() ) {
+ map<int, string>::iterator high = clouds_.find(value->second);
+
+ if ( high != clouds_.end() )
+ {
+ SymbolItem* cloud = new SymbolItem();
+ cloud->x(highColumn_);
+ cloud->y(highRow_);
+ cloud->colour(*owner_->high_colour_);
+ cloud->symbol(high->second);
+
+ MagLog::debug() << "\tHigh Cloud--->" <<value->second << "-->" << high->second << "\n";
+
+ cloud->height(owner_->size_);
+ symbol.add(cloud);
+ }
}
}
@@ -831,7 +1000,7 @@ void ObsSeaTemperature::operator()(CustomisedPoint& point, ComplexSymbol& symb
object->y(row_);
// The temperature is displayed in Celsius.
- double tempe = maground(value->second-273.25);
+ double tempe = maground(value->second-273.15);
MagLog::debug() << "\tTemperature: " << tempe << " from "<<value->second<<"\n";
diff --git a/src/visualisers/ObsItemFamily.h b/src/visualisers/ObsItemFamily.h
index 700a77b..fc599dd 100644
--- a/src/visualisers/ObsItemFamily.h
+++ b/src/visualisers/ObsItemFamily.h
@@ -57,7 +57,7 @@ public:
if (!owner_->station_ring_visible_) return;
tokens.insert("latitude");
tokens.insert("longitude");
- tokens.insert("cloud_amount");
+ tokens.insert("total_cloud");
}
void operator()(CustomisedPoint&, ComplexSymbol& symbol) const
@@ -76,7 +76,34 @@ protected:
void print(ostream& out) const { out << "ObsStationRing" ; }
};
+class ObsStationTriangle : public ObsItemBox
+{
+public:
+ ObsStationTriangle() {}
+ ~ObsStationTriangle() {}
+ void visit(std::set<string>& tokens)
+ {
+
+ if (!owner_->station_ring_visible_) return;
+
+ }
+
+ void operator()(CustomisedPoint&, ComplexSymbol& symbol) const
+ {
+ if (!owner_->station_ring_visible_) return;
+ SymbolItem* station = new SymbolItem();
+ station->x(column_);
+ station->y(row_);
+ station->colour(*owner_->station_ring_colour_);
+ station->symbol("triangle"); // triangle
+ station->height(owner_->ring_size_*0.5);
+ symbol.add(station);
+ }
+protected:
+ void print(ostream& out) const { out << "ObsStationTriangle" ; }
+
+};
class ObsTimePlot : public ObsItemBox
{
@@ -128,7 +155,10 @@ public:
if (!owner_->wind_visible_) return;
tokens.insert("wind_speed");
tokens.insert("wind_direction");
- tokens.insert("cloud_amount");
+ tokens.insert("total_cloud");
+ tokens.insert("low_cloud");
+ tokens.insert("medium_cloud");
+ tokens.insert("high_cloud");
}
virtual void operator()(CustomisedPoint&, ComplexSymbol&) const;
diff --git a/src/visualisers/ObsPlotting.cc b/src/visualisers/ObsPlotting.cc
index 9328791..3bc5b94 100644
--- a/src/visualisers/ObsPlotting.cc
+++ b/src/visualisers/ObsPlotting.cc
@@ -37,6 +37,8 @@ using namespace magics;
ObsPlotting::ObsPlotting()
{
ObsTable::print();
+ if ( ring_size_ == -1 )
+ ring_size_ = size_ * 1.5;
}
ObsPlotting::~ObsPlotting()
@@ -117,6 +119,7 @@ void ObsPlotting::visit(MetaDataVisitor& visitor)
#include "ObsItemFamily.h"
+static SimpleObjectMaker<ObsStationTriangle, ObsItem> ObsStationTriangle("obs_station_triangle");
static SimpleObjectMaker<ObsStationRing, ObsItem> ObsStationRing("obs_station_ring");
static SimpleObjectMaker<ObsTimePlot, ObsItem> ObsTimePlot("obs_time_plot");
static SimpleObjectMaker<ObsWind, ObsItem> ObsWind("obs_wind");
diff --git a/src/visualisers/ObsTable.cc b/src/visualisers/ObsTable.cc
index 3b2d383..8d655f3 100644
--- a/src/visualisers/ObsTable.cc
+++ b/src/visualisers/ObsTable.cc
@@ -156,7 +156,8 @@ void ObsTemplate::operator()(CustomisedPoint& obs, BasicGraphicsObjectContainer&
symbol->push_back(pp);
symbol->setDistanceApart(apart_);
- symbol->setHeight(height_);
+
+ symbol->setHeight(height_*0.5);
out.push_back(symbol);
diff --git a/src/visualisers/SegmentJoiner.cc b/src/visualisers/SegmentJoiner.cc
index 2ac413c..370d6d6 100644
--- a/src/visualisers/SegmentJoiner.cc
+++ b/src/visualisers/SegmentJoiner.cc
@@ -54,7 +54,7 @@ public:
hashSize_ = (1<<bits_);
// Size of the hash table
-
+
while(hashSize_ <= count && bits_ < MAX_BITS) {
bits_ += 2;
hashSize_ = (1<<bits_);
@@ -547,7 +547,7 @@ bool SegmentJoiner::pointInPoly(const Point &p, const vector<Point> &poly) {
return (n%2 == 1);
}
-double SegmentJoiner::punchHoles(vector<vector<Point> > &result) {
+void SegmentJoiner::punchHoles(vector<vector<Point> > &result) {
vector<vector<Point> > polys;
list<vector<Point> > holes;
for(vector<vector<Point> >::iterator j = result.begin() ; j != result.end(); ++j) {
diff --git a/src/visualisers/SegmentJoiner.h b/src/visualisers/SegmentJoiner.h
index 1d48938..3307bd1 100644
--- a/src/visualisers/SegmentJoiner.h
+++ b/src/visualisers/SegmentJoiner.h
@@ -138,8 +138,7 @@ public:
double computeSegmentLines(list<deque<Segment> >& result);
- double punchHoles(vector<vector<Point> >& result);
-
+ void punchHoles(vector<vector<Point> >& result);
static double area(const vector<Point>& );
static bool isHole(const vector<Point>& p) { return area(p) < 0; }
diff --git a/src/visualisers/ShadingTechnique.h b/src/visualisers/ShadingTechnique.h
index 473359e..6e7bddd 100644
--- a/src/visualisers/ShadingTechnique.h
+++ b/src/visualisers/ShadingTechnique.h
@@ -73,7 +73,7 @@ public:
virtual int rightIndex(double) { return -1; }
virtual CellArray* array(MatrixHandler& matrix, IntervalMap<int>& range,
const Transformation& transformation, int width, int height,
- float resolution, const string& technique) { assert(0); return 0;}
+ float resolution, const string& technique) { ASSERT(0); return 0;}
virtual bool needClipping() { return false; }
virtual bool method(ContourMethod*) { return false; }
protected:
diff --git a/src/visualisers/Streamlines.cc b/src/visualisers/Streamlines.cc
index c8d43ca..57daf6b 100644
--- a/src/visualisers/Streamlines.cc
+++ b/src/visualisers/Streamlines.cc
@@ -1,10 +1,12 @@
+
+
/******************************** LICENSE ********************************
Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
@@ -18,13 +20,13 @@
/*! \file WindPlotting.cc
\brief Implementation of the Template class Wind.
-
+
Magics Team - ECMWF 2005
-
+
Started: Thu 17-Mar-2005
-
+
Changes:
-
+
*/
#include "Streamlines.h"
@@ -32,49 +34,63 @@
#include "CalcStreamlines.h"
#include "Timer.h"
#include "Polyline.h"
-
+#include "GeoRectangularProjection.h"
using namespace magics;
bool Streamlines::operator()(Data& data, BasicGraphicsObjectContainer& parent)
{
- Timer timer("Streamlines", "Streamlines");
+ Timer timer("Streamlines", "Streamlines");
- const Transformation& transformation = parent.transformation();
+ const Transformation& transformation = parent.transformation();
- MatrixHandler* handler = transformation.prepareData(data.direction());
+ GeoRectangularProjection geo;
+ MatrixHandler& dir = data.direction();
+ //Make sure that the data are prepared correcly for the Streamlines..
- float* direction = new float[handler->rows()*handler->columns()];
- int i = 0;
- for (int row = 0; row < handler->rows(); row++ )
- for (int column = 0; column < handler->columns(); column++ ) {
- direction[i] = (*handler)(row, column);
- i++;
- }
+ if (dir.right() - dir.left() < 350) {
+ geo.setMinX(dir.left()+1);
+ geo.setMaxX(dir.right()-1);
+ geo.setMinY(dir.bottom()+1);
+ geo.setMaxY(dir.top()-1);
+ }
+ MatrixHandler& handler = *geo.prepareData(data.direction());
- GSStruct *gs = new GSStruct();
- gs->nx = handler->columns();
- gs->ny = handler->rows();
- gs->startx = handler->column(0,0);
- gs->starty = handler->row(0,0);
+ float* direction = new float[handler.rows()*handler.columns()];
+ int i = 0;
+ for (int row = 0; row < handler.rows(); row++ )
+ for (int column = 0; column < handler.columns(); column++ ) {
+ direction[i] = (handler)(row, column);
+ i++;
+ }
- // Distance between the gridpoints
- gs->dx = handler->XResolution();
- gs->dy = -handler->YResolution();
- gs->period_x = 0;
- OneLineClass ** result = 0;
- int size;
+ GSStruct *gs = new GSStruct();
+ gs->nx = handler.columns();
+ gs->ny = handler.rows();
- CalcStreamlines(min_density_, direction, gs, result, size);
+ gs->startx = handler.column(0,0);
+ gs->starty = handler.row(0,0);
- for(int l = 0; l < size; l++)
+ // Distance between the gridpoints
+ gs->dx = handler.XResolution();
+ gs->dy = -handler.YResolution();
+ gs->period_x = 0.;
+ transformation.geoProjection(gs->gs_geo);
+
+ OneLineClass ** result = 0;
+ int size;
+
+
+ CalcStreamlines(min_density_, direction, gs, result, size);
+
+ for(int l = 0; l < size; l++)
{
Polyline poly;
@@ -82,19 +98,21 @@ bool Streamlines::operator()(Data& data, BasicGraphicsObjectContainer& parent)
poly.setThickness(thickness_);
poly.setLineStyle(style_);
+
ArrowProperties* arrow = new ArrowProperties();
+ arrow->setHeadIndex(head_);
+ arrow->setHeadRatio(ratio_);
poly.setArrow(arrow);
for(int i = 0; i < result[l]->Len; i++)
{
- //if (result[l]->X[i] > 180) result[l]->X[i] -= 360;
- poly.push_back(transformation(UserPoint(result[l]->X[i], result[l]->Y[i])));
- transformation(poly, parent);
+ poly.push_back(transformation(UserPoint(result[l]->X[i], result[l]->Y[i])));
+
}
+ transformation(poly, parent);
}
- delete handler;
- return true;
+ return true;
}
void Streamlines::visit(LegendVisitor& legend)
@@ -104,8 +122,9 @@ void Streamlines::visit(LegendVisitor& legend)
void Streamlines::print(ostream& out) const
{
- out << "Streamlines[";
- StreamlinesAttributes::print(out);
- out << "]";
+ out << "Streamlines[";
+ StreamlinesAttributes::print(out);
+ out << "]";
}
+
diff --git a/src/visualisers/SymbolAdvancedTableMode.cc b/src/visualisers/SymbolAdvancedTableMode.cc
index 63b2f72..9bc2d27 100644
--- a/src/visualisers/SymbolAdvancedTableMode.cc
+++ b/src/visualisers/SymbolAdvancedTableMode.cc
@@ -120,11 +120,13 @@ void SymbolAdvancedTableMode::adjust(double min, double max)
if ( markers_.empty() ) {
markers_.push_back(15);
}
+ if ( markers_names_.empty() ) {
+ markers_names_.push_back("ww_01");
+ }
TextSymbol::TextPosition position;
-
if ( text_list_.empty() ) {
position = TextSymbol::M_NONE;
text_list_.push_back("");
@@ -144,12 +146,22 @@ void SymbolAdvancedTableMode::adjust(double min, double max)
LevelSelection::const_iterator level = levels_->begin();
vector<int>::const_iterator marker = markers_.begin();
+ vector<string>::const_iterator marker_name = markers_names_.begin();
+ bool index = magCompare(parent_->marker_mode_, "index");
SymbolProperties last;
vector<string>::const_iterator text = text_list_.begin();
while ( true) {
if (level+1 == levels_->end() ) break;
+
MagLog::debug() << "[" << *level << ", " << *(level+1) << "]=" << *marker << "(marker)" << *text << "(text)"<< endl;
- SymbolProperties properties(colourMethod_->right(*level), height_method_->height(*level), *marker, *text);
+
+ SymbolProperties properties;
+ if ( index )
+ properties = SymbolProperties(colourMethod_->right(*level), height_method_->height(*level), *marker, *text);
+ else
+
+ properties = SymbolProperties(colourMethod_->right(*level), height_method_->height(*level), *marker_name, *text);
+
properties.position_ = position;
properties.font_ = font;
@@ -162,6 +174,7 @@ void SymbolAdvancedTableMode::adjust(double min, double max)
properties.connectLineColour_ = (parent_->automatic_connect_colour_ ) ? colourMethod_->right(*level) : *parent_->connect_colour_;
properties.connectLineStyle_ = parent_->connect_style_;
properties.connectLineThickness_ = parent_->connect_thickness_;
+ properties.blanking_ = parent_->text_blanking_;
last = properties;
map_[Interval(*level, *(level+1)) ] = properties;
@@ -171,6 +184,12 @@ void SymbolAdvancedTableMode::adjust(double min, double max)
}
else
marker++;
+ if ( marker_name+1 == markers_names_.end() ) {
+ if ( marker_policy_ == M_CYCLE )
+ marker_name = markers_names_.begin();
+ }
+ else
+ marker_name++;
if ( text+1 == text_list_.end() ) {
if ( text_policy_ == M_CYCLE )
text = text_list_.begin();
@@ -226,22 +245,25 @@ void SymbolAdvancedTableMode::visit(Data& data, LegendVisitor& legend)
}
case LegendMethod::DISJOINT:
{
- for ( IntervalMap<SymbolProperties>::iterator interval = first; interval != last; ++interval) {
+ for ( IntervalMap<SymbolProperties>::iterator interval = first; interval != last; ++interval) {
+ if ( magCompare(interval->second.marker_, "none") )
+ // ignore entry
+ continue;
Symbol* symbol = new Symbol();
(*symbol).setColour(interval->second.colour_);
(*symbol).setSymbol(interval->second.marker_);
(*symbol).setHeight(interval->second.height_);
-
- string str=data.legendText(interval->first.min_,interval->first.max_);
- if(str.empty())
- {
+
+ string str=data.legendText(interval->first.min_,interval->first.max_);
+ if(str.empty())
+ {
ostringstream text;
text << interval->first.min_ << "-" << interval->first.max_;
- str=text.str();
- }
- legend.add(new SimpleSymbolEntry(interval->second.label_.empty() ? str : interval->second.label_, symbol));
+ str=text.str();
+ }
+ legend.add(new SimpleSymbolEntry(interval->second.label_.empty() ? str : interval->second.label_, symbol));
}
- break;
+ break;
}
case LegendMethod::HISTOGRAM:
{
diff --git a/src/visualisers/SymbolMode.cc b/src/visualisers/SymbolMode.cc
index 7e1ec7b..7781c03 100644
--- a/src/visualisers/SymbolMode.cc
+++ b/src/visualisers/SymbolMode.cc
@@ -139,6 +139,7 @@ void SymbolIndividualMode::properties() const
properties_.connectLineColour_ = (parent_->automatic_connect_colour_) ? *colour_ : *parent_->connect_colour_;
properties_.connectLineStyle_ = parent_->connect_style_;
properties_.connectLineThickness_ = parent_->connect_thickness_;
+ properties_.blanking_ = parent_->text_blanking_;
if ( current_ != text_.end() ) {
properties_.label(*current_);
@@ -152,7 +153,7 @@ void SymbolIndividualMode::properties() const
font.size(text_font_size_);
font.style(text_font_style_);
properties_.font_ = font;
- properties_.blanking_ = text_blanking_;
+
properties_.position_ = position;
properties_.setSymbol(symbol_, 0);
@@ -235,7 +236,7 @@ void SymbolTableMode::prepare()
for (doublearray::const_iterator min = min_.begin(); min != min_.end(); ++min) {
map_[Interval(*min, *max) ] = SymbolProperties(Colour(*colour), *height, *symbol);
-
+ map_[Interval(*min, *max) ].blanking_ = parent_->text_blanking_;
if ( ++colour == colour_.end()) --colour;
if ( ++height == height_.end()) --height;
if ( ++symbol == symbol_.end()) --symbol;
diff --git a/src/visualisers/SymbolPlotting.cc b/src/visualisers/SymbolPlotting.cc
index 54e85bc..852aa12 100644
--- a/src/visualisers/SymbolPlotting.cc
+++ b/src/visualisers/SymbolPlotting.cc
@@ -61,7 +61,7 @@ void SymbolPlotting::operator()(const PaperPoint& point, BasicGraphicsObjectCont
try {
-
+ if ( point.missing() ) return;
if ( (*mode_).accept(point.value()) == false ) return;
SymbolProperties properties = (*mode_)(point.value());
@@ -155,6 +155,8 @@ void SymbolPlotting::operator()(Data& data, BasicGraphicsObjectContainer& out)
// Some Mode need to know the min and max of the data, in order to adjust the
// computation of the levels
(*mode_).adjust(points.min(), points.max());
+ if ( legend_only_ )
+ return;
points.setToFirst();
while (points.more()) {
@@ -174,7 +176,7 @@ void SymbolPlotting::operator()(Data& data, BasicGraphicsObjectContainer& out)
std::sort(work.begin(), work.end(), SortHelper());
- // Now we feed the task...
+ // Now we feed the task... f
for (vector<Symbol* >::iterator symbol = work.begin(); symbol != work.end(); ++symbol) {
if ( !(*symbol)->empty() ) {
diff --git a/src/visualisers/SymbolPlotting.h b/src/visualisers/SymbolPlotting.h
index 49f8028..febb1b0 100644
--- a/src/visualisers/SymbolPlotting.h
+++ b/src/visualisers/SymbolPlotting.h
@@ -57,7 +57,7 @@ public:
bool needLegend() { return legend_; }
virtual void visit(Data&, HistoVisitor&);
void operator()(const PaperPoint&, BasicGraphicsObjectContainer&) const;
-
+ void getReady(const LegendVisitor& legend) { legend_only_ = legend.only_; }
void set(const map<string, string>& map ) { SymbolPlottingAttributes::set(map); }
void set(const XmlNode& node ) { SymbolPlottingAttributes::set(node); }
diff --git a/src/visualisers/Wind.cc b/src/visualisers/Wind.cc
index 953c1ec..dc0f4fa 100644
--- a/src/visualisers/Wind.cc
+++ b/src/visualisers/Wind.cc
@@ -86,8 +86,8 @@ void Wind::operator()(Data& data, BasicGraphicsObjectContainer& parent)
request.insert("x_component");
request.insert("y_component");
request.insert("colour_component");
- if ( thinning_debug_ )
- request.insert("debug");
+ //if ( thinning_debug_ )
+ //request.insert("debug");
(*method)(data, transformation, request, points);
if (points.empty() )
return;
diff --git a/src/visualisers/WindPlotting.h b/src/visualisers/WindPlotting.h
index 869a34f..52dc224 100644
--- a/src/visualisers/WindPlotting.h
+++ b/src/visualisers/WindPlotting.h
@@ -104,8 +104,8 @@ protected:
void setNormal(double&, double&) {}
IntervalMap<Colour> map_;
- virtual double minSpeed() { assert(false); return 0;}
- virtual double maxSpeed() { assert(false); return 0;}
+ virtual double minSpeed() { NOTIMP; return 0;}
+ virtual double maxSpeed() { NOTIMP; return 0;}
private:
diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt
index 801fe1d..c216047 100644
--- a/src/web/CMakeLists.txt
+++ b/src/web/CMakeLists.txt
@@ -2,6 +2,7 @@ set( _web_srcs
MagJSon.cc ObsJSon.cc WrepJSon.h json_spirit_reader.h json_spirit_value.h
MagConfig.cc MagJSon.h ObsJSon.h json_spirit.h json_spirit_utils.h json_spirit_writer.cpp
MagConfig.h WrepJSon.cc json_spirit_reader.cpp json_spirit_value.cpp json_spirit_writer.h json_spirit_writer_options.h
+GeoJSon.h GeoJSon.cc
)
diff --git a/src/web/GeoJSon.cc b/src/web/GeoJSon.cc
new file mode 100644
index 0000000..10040eb
--- /dev/null
+++ b/src/web/GeoJSon.cc
@@ -0,0 +1,135 @@
+/******************************** LICENSE ********************************
+
+ Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ ******************************** LICENSE ********************************/
+
+
+/*!
+ \brief Implementation of the Template class SpotDecoder.
+
+ Magics Team - ECMWF 2005
+
+ Started: Mon 19-Sep-2005
+
+ Changes:
+
+*/
+
+
+
+#include "GeoJSon.h"
+
+
+
+using namespace magics;
+using namespace json_spirit;
+
+
+
+GeoJSon::GeoJSon()
+{
+ methods_["coordinates"] = &GeoJSon::coordinates;
+ methods_["type"] = &GeoJSon::type;
+ methods_["properties"] = &GeoJSon::properties;
+}
+
+GeoJSon::~GeoJSon()
+{
+
+}
+
+void GeoJSon::print(ostream& out) const
+{
+ out <<"ObsJSon[";
+ GeoJSonAttributes::print(out);
+ out << "]";
+}
+void GeoJSon::coordinates(const json_spirit::Value& value)
+{
+ Array lines = value.get_value< Array>();
+ for (unsigned int i = 0; i < lines.size(); i++) {
+ Array line = lines[i].get_value< Array >();
+ for (unsigned int pt = 0; pt < line.size(); pt++) {
+ Array point = line[pt].get_value< Array >();
+ push_back(new UserPoint(point[0].get_value<double>(), point[1].get_value<double>()));
+ }
+ push_back(new UserPoint(0,0,0,true));
+ }
+}
+void GeoJSon::properties(const json_spirit::Value&)
+{
+
+}
+
+void GeoJSon::type(const json_spirit::Value&)
+{
+
+}
+
+void GeoJSon::decode()
+{
+ points_.clear();
+
+ try {
+ json_spirit::Value value;
+ if ( magCompare(type_, "string" ) ) {
+ istringstream is(input_);
+ json_spirit::read_or_throw(is, value );
+ }
+ else {
+ ifstream is(path_.c_str());
+ json_spirit::read_or_throw(is, value );
+ }
+
+ Object object = value.get_value< Object >();
+
+
+
+ for (vector<Pair>::const_iterator entry = object.begin(); entry != object.end(); ++entry) {
+ map<string, Method >::iterator method = methods_.find(entry->name_);
+ if ( method != methods_.end() ) {
+ ( (this->*method->second)(entry->value_) );
+ }
+
+ }
+ }
+ catch (std::exception e) {
+ MagLog::error() << "Could not processed the file: " << path_ << ": " << e.what() << endl;
+ abort();
+ }
+
+}
+
+
+
+void GeoJSon::points(const Transformation& transformation, vector<UserPoint>& points)
+{
+ decode();
+
+}
+
+PointsHandler& GeoJSon::points(const Transformation& transformation, bool)
+{
+ decode();
+ pointsHandlers_.push_back(new PointsHandler(*this));
+ return *(pointsHandlers_.back());
+
+}
+
+void GeoJSon::customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, bool )
+{
+
+}
diff --git a/src/decoders/BoxPlotDecoder.h b/src/web/GeoJSon.h
similarity index 56%
copy from src/decoders/BoxPlotDecoder.h
copy to src/web/GeoJSon.h
index 53c5a9d..203f635 100644
--- a/src/decoders/BoxPlotDecoder.h
+++ b/src/web/GeoJSon.h
@@ -16,66 +16,81 @@
******************************** LICENSE ********************************/
-/*! \file BoxPlotDecoder.h
- \brief Definition of the Template class BoxPlotDecoder.
+/*! \file EpsgramDecoder.h
+ \brief Definition of the Template class EpsgramDecoder.
Magics Team - ECMWF 2005
- Started: Thu 29-Sep-2005
+ Started: Mon 19-Sep-2005
Changes:
*/
-#ifndef BoxPlotDecoder_H
-#define BoxPlotDecoder_H
+#ifndef GeoJSon_H
+#define GeoJSon_H
#include "magics.h"
-#include "BoxPlotDecoderAttributes.h"
-#include "Data.h"
+
+#include "GeoJSonAttributes.h"
+
#include "Decoder.h"
+#include "Data.h"
#include "UserPoint.h"
+#include "DateTime.h"
+#include "json_spirit.h"
+#include "PointsHandler.h"
+
+#include <limits>
namespace magics {
-class BoxPlotDecoder:
- public BoxPlotDecoderAttributes,
- public Data,
- public PointsList {
+
+class GeoJSon:
+ public Data,
+ public PointsList,
+ public GeoJSonAttributes
+{
public:
- BoxPlotDecoder();
- virtual ~BoxPlotDecoder();
+ GeoJSon();
+ virtual ~GeoJSon();
+
+ typedef void (GeoJSon::*Method)(const json_spirit::Value&);
+
+
+ map<string, Method> methods_;
- virtual void set(const map<string, string>& map)
- { BoxPlotDecoderAttributes::set(map); }
+
+
- virtual void set(const XmlNode& node)
- { BoxPlotDecoderAttributes::set(node); }
-
- void customisedPoints(const std::set<string>&, CustomisedPointsList&);
- void customisedPoints(const Transformation& t, const std::set<string>& n, CustomisedPointsList& out, bool all)
- {
- customisedPoints(n, out);
- }
- PointsHandler& points(const Transformation&, bool) { assert(false); }
- void getReady(const Transformation&);
+ void points(const Transformation&, vector<UserPoint>&);
+ void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList&, bool );
+ PointsHandler& points(const Transformation&, bool);
+
+
protected:
//! Method to print string about this class on to a stream of type ostream (virtual).
virtual void print(ostream&) const;
+ void decode();
+ void coordinates(const json_spirit::Value&);
+ void properties(const json_spirit::Value&);
+ void type(const json_spirit::Value&);
+ vector<CustomisedPoint*> points_;
+
+
private:
//! Copy constructor - No copy allowed
- BoxPlotDecoder(const BoxPlotDecoder&);
+ GeoJSon(const GeoJSon&);
//! Overloaded << operator to copy - No copy allowed
- BoxPlotDecoder& operator=(const BoxPlotDecoder&);
+ GeoJSon& operator=(const GeoJSon&);
// -- Friends
//! Overloaded << operator to call print().
- friend ostream& operator<<(ostream& s,const BoxPlotDecoder& p)
+ friend ostream& operator<<(ostream& s,const GeoJSon& p)
{ p.print(s); return s; }
-
};
} // namespace magics
diff --git a/src/web/MagJSon.cc b/src/web/MagJSon.cc
index f7869a8..20aa5b3 100644
--- a/src/web/MagJSon.cc
+++ b/src/web/MagJSon.cc
@@ -51,34 +51,68 @@ void MagJSon::parse(const string& file)
void MagJSon::interpret(const string& def)
{
+
MagLog::dev()<< "interpret-->" << def << endl;
istringstream is(def);
json_spirit::Value value;
json_spirit::read_or_throw(is, value );
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object object = value.get_value< Object >();
//buils the Magics XmlNode!
build(*tree_.root(), "magics", object);
}
+void ParamJSon::magics(const json_spirit::Value& value)
+{
+ ASSERT( value.type() == obj_type );
+ Object object = value.get_value< Object >();
+ for (vector<Pair>::const_iterator entry = object.begin(); entry != object.end(); ++entry)
+ {
+ if ( entry->value_.type() == str_type) {
+ this->insert(make_pair(entry->name_, entry->value_.get_value<string>()));
+ }
+ if ( entry->value_.type() == int_type) {
+ string value = tostring(entry->value_.get_value<int>());
+ this->insert(make_pair(entry->name_, value));
+ }
+ if ( entry->value_.type() ==real_type) {
+ string value = tostring(entry->value_.get_value<double>());
+ this->insert(make_pair(entry->name_, value));
+ }
+
+ }
+}
+
+ParamJSon::ParamJSon(const string& param)
+{
+ if ( param.empty() )
+ return;
+ istringstream is(param);
+ json_spirit::Value value;
+ json_spirit::read_or_throw(is, value);
+ magics(value);
+
+}
+
+
void MagJSon::drivers(XmlNode& parent, const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
XmlNode* drivers = new XmlNode("drivers");
parent.push_back(drivers);
Array all = value.get_value< Array >();
for (Array::iterator entry = all.begin(); entry != all.end(); ++entry) {
- assert( entry->type() == obj_type);
+ ASSERT( entry->type() == obj_type);
Object driver = entry->get_value< Object >();
map<string, string> attributes;
for (vector<Pair>::const_iterator elt = driver.begin(); elt != driver.end(); ++elt) {
- assert(elt->value_.type() == str_type);
+ ASSERT(elt->value_.type() == str_type);
attributes.insert(make_pair(elt->name_, elt->value_.get_value< string >()));
}
map<string, string>::iterator format = attributes.find("format");
- assert(format!=attributes.end());
+ ASSERT(format!=attributes.end());
drivers->push_back(tree_.newNode(format->second, attributes));
}
}
@@ -86,22 +120,22 @@ void MagJSon::drivers(XmlNode& parent, const json_spirit::Value& value)
void MagJSon::definitions(XmlNode& parent, const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
XmlNode* definitions = new XmlNode("definition");
tree_.definition(definitions);
Array all = value.get_value< Array >();
for (Array::iterator entry = all.begin(); entry != all.end(); ++entry) {
- assert( entry->type() == obj_type);
+ ASSERT( entry->type() == obj_type);
Object def = entry->get_value< Object >();
map<string, string> attributes;
for (vector<Pair>::const_iterator elt = def.begin(); elt != def.end(); ++elt) {
- assert(elt->value_.type() == str_type);
+ ASSERT(elt->value_.type() == str_type);
attributes.insert(make_pair(elt->name_, elt->value_.get_value< string >()));
}
map<string, string>::iterator type = attributes.find("class");
- assert(type!=attributes.end());
+ ASSERT(type!=attributes.end());
definitions->push_back(tree_.newNode(type->second, attributes));
}
}
@@ -160,7 +194,7 @@ void MagJSon::build(XmlNode& parent, const string& name, Object& object)
void MagJSon::magics(const json_spirit::Value& value)
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object object = value.get_value< Object >();
XmlMagics magics;
diff --git a/src/web/MagJSon.h b/src/web/MagJSon.h
index f405c12..660fc5b 100644
--- a/src/web/MagJSon.h
+++ b/src/web/MagJSon.h
@@ -67,9 +67,20 @@ protected:
};
+class ParamJSon : public map<string, string>
+{
+public:
+ ParamJSon(const string&);
+ ~ParamJSon() {}
+
+protected:
+ void magics(const json_spirit::Value&);
+};
+
+
} // namespace magics
#endif
diff --git a/src/web/ObsJSon.cc b/src/web/ObsJSon.cc
index 5f4cca2..21acfcb 100644
--- a/src/web/ObsJSon.cc
+++ b/src/web/ObsJSon.cc
@@ -165,19 +165,19 @@ void ObsJSon::getInfo(const std::set<string>& what, multimap<string, string>& in
void ObsJSon::latitude(const json_spirit::Value& value, CustomisedPoint& point)
{
- assert( value.type() == real_type);
+ ASSERT( value.type() == real_type);
point.latitude(value.get_value< double>());
}
void ObsJSon::longitude(const json_spirit::Value& value, CustomisedPoint& point)
{
- assert( value.type() == real_type);
+ ASSERT( value.type() == real_type);
point.longitude(value.get_value< double>());
}
void ObsJSon::type(const json_spirit::Value& value, CustomisedPoint& point)
{
- assert( value.type() == str_type);
+ ASSERT( value.type() == str_type);
string type=value.get_value<string>();
point.type(type);
types_.insert(type);
@@ -185,7 +185,7 @@ void ObsJSon::type(const json_spirit::Value& value, CustomisedPoint& point)
void ObsJSon::identifier(const json_spirit::Value& value, CustomisedPoint& point)
{
- assert( value.type() == str_type);
+ ASSERT( value.type() == str_type);
string type=value.get_value<string>();
point.identifier(type);
}
diff --git a/src/web/ObsJSon.h b/src/web/ObsJSon.h
index f849179..ca3e9da 100644
--- a/src/web/ObsJSon.h
+++ b/src/web/ObsJSon.h
@@ -57,7 +57,7 @@ public:
void customisedPoints(const Transformation&, const std::set<string>&, CustomisedPointsList& );
void customisedPoints(const Transformation& t, const std::set<string>& n, CustomisedPointsList& out, bool all);
- PointsHandler& points(const Transformation&, bool) { assert(false); }
+ PointsHandler& points(const Transformation&, bool) { NOTIMP; }
virtual void set(const map<string, string>& map) { ObsJSonAttributes::set(map); }
virtual void set(const XmlNode& node) { ObsJSonAttributes::set(node); }
diff --git a/src/web/WrepJSon.cc b/src/web/WrepJSon.cc
index e1bed2a..c8517ee 100644
--- a/src/web/WrepJSon.cc
+++ b/src/web/WrepJSon.cc
@@ -35,6 +35,7 @@
#include "CustomisedPoint.h"
#include "DateTime.h"
#include "TextVisitor.h"
+#include "MagException.h"
#include "json_spirit.h"
#include "IntervalMap.h"
#include "EfiLegendEntry.h"
@@ -47,12 +48,11 @@ static map<char, string> specials;
WrepJSon::WrepJSon() : missing_(-9999),
height_(-9999),
mask_(9999),
- station_latitude_(9999),
- station_longitude_(9999),
- latitude_(0), longitude_(0)
+ latitude_(0), station_longitude_(9999), longitude_(0)
{
methods_["date"] = &WrepJSon::date;
methods_["time"] = &WrepJSon::time;
+ methods_["expver"] = &WrepJSon::expver;
methods_["eps_height"] = &WrepJSon::epsz;
methods_["height"] = &WrepJSon::height;
methods_["deterministic_height"] = &WrepJSon::detz;
@@ -64,6 +64,7 @@ WrepJSon::WrepJSon() : missing_(-9999),
methods_["land_sea_mask"] = &WrepJSon::mask;
methods_["metadata"] = &WrepJSon::metadata;
methods_["points_along_meridian"] = &WrepJSon::points_along_meridian;
+ methods_["valid_time"] = &WrepJSon::valid_time;
methods_["x_values"] = &WrepJSon::x_values;
methods_["x_date_values"] = &WrepJSon::x_date_values;
@@ -193,6 +194,12 @@ void WrepJSon::visit(Transformation& transformation)
decode();
+ if ( miny_ == std::numeric_limits<double>::max() ) {
+ // All data missing
+ miny_ = 0;
+ maxy_ = 0;
+ }
+
double add = (maxy_ - miny_ ) * y_percent_ /100.;
maxy_ += add;
miny_ -= add;
@@ -578,7 +585,7 @@ void WrepJSon::metadata(const json_spirit::Value& value )
void WrepJSon::station(const json_spirit::Value& value )
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object location = value.get_value<Object>();
const json_spirit::Value lat = find_value(location, "lat");
const json_spirit::Value lon = find_value(location, "lon");
@@ -593,7 +600,7 @@ void WrepJSon::station(const json_spirit::Value& value )
void WrepJSon::location(const json_spirit::Value& value )
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object location = value.get_value<Object>();
const json_spirit::Value lat = find_value(location, "lat");
const json_spirit::Value lon = find_value(location, "lon");
@@ -621,7 +628,7 @@ void WrepJSon::station_name(const json_spirit::Value& value )
}
void WrepJSon::epsz(const json_spirit::Value& value)
{
- assert( value.type() == real_type);
+ ASSERT( value.type() == real_type);
epsz_ = value.get_value< double>();
MagLog::dev() << "found -> epsz= " << epsz_ << endl;
}
@@ -638,45 +645,65 @@ void WrepJSon::height(const json_spirit::Value& value)
void WrepJSon::detz(const json_spirit::Value& value )
{
- assert( value.type() == real_type);
+ ASSERT( value.type() == real_type);
detz_ = value.get_value< double>();
MagLog::dev() << "found -> detz= " << detz_ << endl;
}
void WrepJSon::mask(const json_spirit::Value& value )
{
- assert( value.type() == real_type);
+ ASSERT( value.type() == real_type);
mask_ = value.get_value< double>();
MagLog::dev() << "found -> mask= " << mask_ << endl;
}
void WrepJSon::missing(const json_spirit::Value& value )
{
- assert( value.type() == str_type);
+ ASSERT( value.type() == str_type);
MagLog::dev() << "found -> missing= " << value.get_value<string>() << endl;
missing_ = tonumber(value.get_value<string>());
}
void WrepJSon::date(const json_spirit::Value& value)
{
- assert( value.type() == str_type);
+ ASSERT( value.type() == str_type);
MagLog::dev() << "found -> date= " << value.get_value<string>() << endl;
date_ = value.get_value<string>();
}
+void WrepJSon::expver(const json_spirit::Value& value)
+{
+
+ ASSERT( value.type() == str_type);
+ MagLog::dev() << "found -> expver= " << value.get_value<string>() << endl;
+ expver_ = value.get_value<string>();
+
+}
void WrepJSon::time(const json_spirit::Value& value)
{
- assert( value.type() == str_type);
+ ASSERT( value.type() == str_type);
MagLog::dev() << "found -> time= " << value.get_value<string>() << endl;
time_ = value.get_value<string>();
}
+void WrepJSon::valid_time(const json_spirit::Value& value)
+{
+ ASSERT( value.type() == str_type);
+
+ // intrepret datetime ...
+ string info = value.get_value<string>();
+ DateTime to(info.substr(0,8), info.substr(8,4));
+ DateTime from = to + (-24*3600L);
+ ostringstream vt;
+ vt << "from " << from.tostring("%A %e %B %Y %H UTC") << " to " << to.tostring("%A %e %B %Y %H UTC") << endl;
+ valid_time_ = vt.str();
+}
void WrepJSon::parameter(const json_spirit::Value& value)
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object param = value.get_value< Object >();
for (vector<Pair>::const_iterator info = param.begin(); info != param.end(); ++info) {
- assert (info->value_.type() == array_type);
+ ASSERT (info->value_.type() == array_type);
Array values = info->value_.get_value<Array>();
if ( info->name_ == "steps" ) {
for (unsigned int i = 0; i < values.size(); i++) {
@@ -691,6 +718,13 @@ void WrepJSon::parameter(const json_spirit::Value& value)
}
}
else {
+ bool add = true;
+ for ( vector<string>::iterator i = ignore_keys_.begin(); i != ignore_keys_.end(); ++i)
+ if ( *i == info->name_ )
+ add = false;
+ if ( !add ) {
+ continue;
+ }
map<string, vector<double> >& xv = current_->values_;
xv.insert(make_pair(info->name_, vector<double>()));
vector<double>& vals = xv[info->name_];
@@ -717,7 +751,7 @@ void WrepJSon::parameter(const json_spirit::Value& value)
}
void WrepJSon::dig(const json_spirit::Value& value)
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object object = value.get_value< Object >();
for (vector<Pair>::const_iterator entry = object.begin(); entry != object.end(); ++entry) {
map<string, Method >::iterator method = methods_.find(entry->name_);
@@ -950,7 +984,7 @@ void WrepJSon::clim(const json_spirit::Value& value)
dig(value);
- clim_.print();
+ //clim_.print();
@@ -958,7 +992,7 @@ void WrepJSon::clim(const json_spirit::Value& value)
void WrepJSon::efi(const json_spirit::Value& value)
{
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object param = value.get_value< Object >();
scaling_factor_ = 100;
offset_factor_ = 0;
@@ -969,11 +1003,12 @@ void WrepJSon::efi(const json_spirit::Value& value)
current_ = &(efi_[info->name_]);
dig(info->value_);
}
-
+ /*
for (map<string, InputWrep>::iterator info = efi_.begin(); info != efi_.end(); ++info) {
info->second.print();
}
+ */
}
@@ -983,7 +1018,7 @@ void WrepJSon::eps(const json_spirit::Value& value)
scaling_factor_ = param_scaling_factor_;
offset_factor_ = param_offset_factor_;
- assert( value.type() == obj_type );
+ ASSERT( value.type() == obj_type );
Object param = value.get_value< Object >();
for (vector<Pair>::const_iterator info = param.begin(); info != param.end(); ++info) {
@@ -992,11 +1027,12 @@ void WrepJSon::eps(const json_spirit::Value& value)
current_ = &(eps_[info->name_]);
dig(info->value_);
}
-
+ /*
for (map<string, InputWrep>::iterator info = eps_.begin(); info != eps_.end(); ++info) {
- info->second.print();
+ //info->second.print();
}
+ */
}
double WrepJSon::correctDetz(double value)
@@ -1071,14 +1107,14 @@ Value WrepJSon::temperature_adjustment()
void WrepJSon::points_along_meridian(const json_spirit::Value& value)
{
- assert( value.type() == int_type);
+ ASSERT( value.type() == int_type);
points_along_meridian_ = value.get_value< int>();
MagLog::dev() << "found -> points_along_meridian_mask= " << mask_ << endl;
}
void WrepJSon::x_values(const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
Array values = value.get_value<Array>();
bool newpoint = points_.empty();
vector<double> minmax;
@@ -1105,7 +1141,7 @@ void WrepJSon::x_values(const json_spirit::Value& value)
}
void WrepJSon::values(const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
Array values = value.get_value<Array>();
bool newpoint = points_.empty();
@@ -1129,7 +1165,7 @@ void WrepJSon::values(const json_spirit::Value& value)
}
void WrepJSon::y_values(const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
Array values = value.get_value<Array>();
bool newpoint = points_.empty();
vector<double> minmax;
@@ -1161,7 +1197,7 @@ void WrepJSon::y_values(const json_spirit::Value& value)
void WrepJSon::x_date_values(const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
Array values = value.get_value<Array>();
if ( !regular_) {
xdate_ = true;
@@ -1195,7 +1231,7 @@ void WrepJSon::x_date_values(const json_spirit::Value& value)
void WrepJSon::y_date_values(const json_spirit::Value& value)
{
- assert (value.type() == array_type);
+ ASSERT (value.type() == array_type);
Array values = value.get_value<Array>();
ydate_ = true;
yBase_ = DateTime(values[0].get_value<string>());
@@ -1282,10 +1318,15 @@ void WrepJSon::visit(TextVisitor& text)
if (param_info_ != "none")
text.update("json", "station_name", station_name_);
- //(**point)["y"]
- text.update("json", "product_info", product_info_);
- text.update("json", "plumes_interval", tostring(plumes_));
+
+ if ( !expver_.empty() && expver_ != "0001") {
+ text.update("json", "expver", " [" + expver_ + "] ");
+ }
+ text.update("json", "product_info", product_info_);
+ text.update("json", "plumes_interval", tostring(plumes_));
+ text.update("json", "efi_date", valid_time_);
+ text.update("json", "min_max_values", "Max = " + tostring(maground(maxx_)) + ", Min = " + tostring(maground(minx_)));
}
void WrepJSon::points(const Transformation& transformation, vector<UserPoint>& points)
diff --git a/src/web/WrepJSon.h b/src/web/WrepJSon.h
index e950f1f..5269120 100644
--- a/src/web/WrepJSon.h
+++ b/src/web/WrepJSon.h
@@ -35,11 +35,12 @@
#include "WrepJSonAttributes.h"
+#include "json_spirit.h"
#include "Decoder.h"
#include "Data.h"
#include "UserPoint.h"
#include "DateTime.h"
-#include "json_spirit.h"
+
#include "Matrix.h"
#include <limits>
@@ -124,11 +125,14 @@ public:
void location(const json_spirit::Value&);
void station_name(const json_spirit::Value&);
+ void valid_time(const json_spirit::Value&);
void epsz(const json_spirit::Value&);
void detz(const json_spirit::Value&);
void date(const json_spirit::Value&);
+ void expver(const json_spirit::Value&);
void height(const json_spirit::Value&);
void time(const json_spirit::Value&);
+
virtual void parameter(const json_spirit::Value&);
virtual void eps(const json_spirit::Value&);
virtual void clim(const json_spirit::Value&);
@@ -199,6 +203,9 @@ protected:
string date_;
string time_;
string file_;
+ string valid_time_;
+ string expver_;
+
json_spirit::Value metadata_;
InputWrep values_;
InputWrep* current_;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 5db4071..28682b1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,110 +1,96 @@
-
-
-
# Basic test
ecbuild_add_test( TARGET basic_c
- SOURCES coast.c
- LIBS MagPlusSingleShared MagPlusShared
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE C )
+ SOURCES coast.c
+ LIBS MagPlusSingle MagPlus
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE C )
+
+ecbuild_add_test( TARGET basic_python
+ TYPE PYTHON
+ CONDITION HAVE_PYTHON
+ ARGS coast.py
+ RESOURCES coast.py
+ ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH}
+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib
+ MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/.. )
+ecbuild_add_test( TARGET basic_fortran_shared
+ SOURCES coast.f90
+ LIBS MagPlusSingle MagPlus
+ CONDITION HAVE_FORTRAN
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE Fortran )
-if ( ENABLE_PYTHON )
- ecbuild_add_test( TARGET basic_python
- TYPE PYTHON
- ARGS coast.py
- RESOURCES coast.py
- ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH} MAGPLUS_HOME=${CMAKE_SOURCE_DIR} )
-endif()
+ecbuild_add_test( TARGET basic_fortran_static
+ SOURCES coast.f90
+ LIBS MagPlusSingleStatic MagPlusStatic ${MAGICS_EXTRA_LIBRARIES}
+ CONDITION HAVE_FORTRAN AND BUILD_SHARED_LIBS STREQUAL "BOTH"
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE Fortran )
-if ( ENABLE_FORTRAN)
- ecbuild_add_test( TARGET basic_fortran_shared
- SOURCES coast.f90
- LIBS MagPlusSingleShared MagPlusShared
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE Fortran )
- if ( ENABLE_STATIC_LIBRARY )
- ecbuild_add_test( TARGET basic_fortran_static
- SOURCES coast.f90
- LIBS MagPlusSingleStatic MagPlusStatic ${MAGICS_EXTRA_LIBRARIES}
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE Fortran )
- endif()
-endif()
-
-if ( ENABLE_BUFR )
- if ( ENABLE_PYTHON )
- ecbuild_add_test( TARGET bufr_python
+ecbuild_add_test( TARGET bufr_python
TYPE PYTHON
+ CONDITION HAVE_BUFR AND HAVE_PYTHON
ARGS bufr.py
RESOURCES bufr.py data.bufr
- ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH} MAGPLUS_HOME=${CMAKE_SOURCE_DIR})
- endif()
- if ( ENABLE_FORTRAN)
- ecbuild_add_test( TARGET bufr_fortran
- SOURCES bufr.f90
- LIBS MagPlusSingleShared MagPlusShared
- RESOURCES data.bufr
- LINKER_LANGUAGE Fortran
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR})
- if ( ENABLE_STATIC_LIBRARY )
- ecbuild_add_test( TARGET bufr_fortran_static
- SOURCES bufr.f90
- RESOURCES data.bufr
- LIBS MagPlusSingleStatic MagPlusStatic
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE Fortran )
- endif()
- endif()
-endif()
+ ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH}
+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib
+ MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/.. )
+ecbuild_add_test( TARGET bufr_fortran
+ SOURCES bufr.f90
+ LIBS MagPlusSingle MagPlus
+ CONDITION HAVE_BUFR AND HAVE_FORTRAN
+ RESOURCES data.bufr
+ LINKER_LANGUAGE Fortran
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..)
+ecbuild_add_test( TARGET bufr_fortran_static
+ SOURCES bufr.f90
+ RESOURCES data.bufr
+ LIBS MagPlusSingleStatic MagPlusStatic
+ CONDITION HAVE_BUFR AND HAVE_FORTRAN AND BUILD_SHARED_LIBS STREQUAL "BOTH"
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE Fortran )
-
-if ( ENABLE_GRIB )
- if ( ENABLE_PYTHON )
- ecbuild_add_test( TARGET grib_python
+ecbuild_add_test( TARGET grib_python
TYPE PYTHON
+ CONDITION HAVE_GRIB AND HAVE_PYTHON
ARGS grib.py
RESOURCES grib.py data.grib
- ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH} MAGPLUS_HOME=${CMAKE_SOURCE_DIR})
- endif()
- if ( ENABLE_FORTRAN)
- ecbuild_add_test( TARGET grib_fortran
- SOURCES grib.f90
- LIBS MagPlusSingleShared MagPlusShared
- RESOURCES data.grib
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE Fortran )
- endif()
-endif()
-
+ ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH}
+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib
+ MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/.. )
+ecbuild_add_test( TARGET grib_fortran
+ SOURCES grib.f90
+ LIBS MagPlusSingle MagPlus
+ RESOURCES data.grib
+ CONDITION HAVE_GRIB AND HAVE_FORTRAN
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE Fortran )
-if ( ENABLE_CAIRO )
- if ( ENABLE_PYTHON )
- ecbuild_add_test( TARGET cairo_python
+ecbuild_add_test( TARGET cairo_python
TYPE PYTHON
+ CONDITION HAVE_CAIRO AND HAVE_PYTHON
ARGS cairo.py
RESOURCES cairo.py
- ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH} MAGPLUS_HOME=${CMAKE_SOURCE_DIR})
- endif()
- if ( ENABLE_FORTTAN )
- ecbuild_add_test( TARGET cairo_fortran
- SOURCES cairo.f90
- LIBS MagPlusSingleShared MagPlusShared
- ENVIRONMENT MAGPLUS_HOME=${CMAKE_SOURCE_DIR}
- LINKER_LANGUAGE Fortran )
- endif()
-endif()
+ ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH}
+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib
+ MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/.. )
-if ( ENABLE_ODB )
- if ( ENABLE_PYTHON )
- ecbuild_add_test( TARGET odb_python
+ecbuild_add_test( TARGET cairo_fortran
+ SOURCES cairo.f90
+ LIBS MagPlusSingle MagPlus
+ CONDITION HAVE_CAIRO AND HAVE_FORTRAN
+ ENVIRONMENT MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/..
+ LINKER_LANGUAGE Fortran )
+
+ecbuild_add_test( TARGET odb_python
TYPE PYTHON
+ CONDITION HAVE_ODB AND HAVE_PYTHON
ARGS odb.py
RESOURCES odb.py test.odb
- ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH} MAGPLUS_HOME=${CMAKE_SOURCE_DIR} )
- endif()
-endif()
-
+ ENVIRONMENT PYTHONPATH=${MAG_PYTHON_PATH}
+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib
+ MAGPLUS_HOME=${CMAKE_CURRENT_SOURCE_DIR}/.. )
diff --git a/test/Testing/Temporary/CTestCostData.txt b/test/Testing/Temporary/CTestCostData.txt
deleted file mode 100644
index ed97d53..0000000
--- a/test/Testing/Temporary/CTestCostData.txt
+++ /dev/null
@@ -1 +0,0 @@
----
diff --git a/tools/xml2cc_new.pl b/tools/xml2cc_new.pl
index 56fba98..f764d21 100755
--- a/tools/xml2cc_new.pl
+++ b/tools/xml2cc_new.pl
@@ -21,6 +21,7 @@ my %basetype = (
"floatarray" =>1,
"stringarray" => 1,
"intarray" => 1,
+ "longintarray" => 1,
"LineStyle" =>1,
"ListPolicy" =>1,
"Hemisphere" =>1,
@@ -46,7 +47,8 @@ my %translator = (
"bool" => "ParameterManager::getBool",
"doublearray" => "ParameterManager::getDoubleArray",
"floatarray" => "ParameterManager::getDoubleArray",
- "intarray" => "ParameterManager::getIntArray"
+ "intarray" => "ParameterManager::getIntArray",
+ "longintarray" => "ParameterManager::getLongIntArray"
);
my %magtype = (
@@ -66,6 +68,7 @@ my %arraytype = (
"floatarray" => "atof(data)",
"stringarray" => "data",
"intarray" => "atoi(data)",
+ "longintarray" => "atoi(data)",
);
my %quote = (
diff --git a/tools/xml2mv.pl b/tools/xml2mv.pl
index f73f118..d3c411b 100755
--- a/tools/xml2mv.pl
+++ b/tools/xml2mv.pl
@@ -24,6 +24,7 @@ my %basetype = (
"stringarray" => 1,
"stringarray" => 1,
"intarray" => 1,
+ "longintarray" => 1,
"LineStyle" =>1,
"Hemisphere" =>1,
"ArrowPosition" => 1,
@@ -44,6 +45,7 @@ my %arraytype = (
"doublearray" => "atof(data)",
"stringarray" => "data",
"intarray" => "atoi(data)",
+ "longintarray" => "atoi(data)",
);
my %pointertype = {
@@ -409,6 +411,7 @@ EOF
"floatarray" => "(double)",
"stringarray" => "(string)",
"intarray" => "(int)",
+ "longintarray" => "(long int)",
);
my %pointertype = (
"Colour" => "1",
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/magics.git
More information about the debian-science-commits
mailing list